diff options
Diffstat (limited to 'scene/main')
-rw-r--r-- | scene/main/canvas_item.cpp | 319 | ||||
-rw-r--r-- | scene/main/canvas_item.h | 129 | ||||
-rw-r--r-- | scene/main/canvas_layer.h | 1 | ||||
-rw-r--r-- | scene/main/http_request.cpp | 56 | ||||
-rw-r--r-- | scene/main/http_request.h | 6 | ||||
-rw-r--r-- | scene/main/instance_placeholder.cpp | 22 | ||||
-rw-r--r-- | scene/main/node.cpp | 378 | ||||
-rw-r--r-- | scene/main/node.h | 76 | ||||
-rw-r--r-- | scene/main/scene_tree.cpp | 210 | ||||
-rw-r--r-- | scene/main/scene_tree.h | 51 | ||||
-rw-r--r-- | scene/main/shader_globals_override.cpp | 17 | ||||
-rw-r--r-- | scene/main/shader_globals_override.h | 2 | ||||
-rw-r--r-- | scene/main/timer.cpp | 14 | ||||
-rw-r--r-- | scene/main/timer.h | 10 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 1468 | ||||
-rw-r--r-- | scene/main/viewport.h | 214 | ||||
-rw-r--r-- | scene/main/window.cpp | 281 | ||||
-rw-r--r-- | scene/main/window.h | 19 |
18 files changed, 1536 insertions, 1737 deletions
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index db55f4feb7..64b169b1fb 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -30,292 +30,17 @@ #include "canvas_item.h" -#include "core/input/input.h" #include "core/object/message_queue.h" #include "scene/2d/canvas_group.h" #include "scene/main/canvas_layer.h" -#include "scene/main/viewport.h" #include "scene/main/window.h" +#include "scene/resources/canvas_item_material.h" #include "scene/resources/font.h" +#include "scene/resources/multimesh.h" #include "scene/resources/style_box.h" -#include "scene/resources/texture.h" +#include "scene/resources/world_2d.h" #include "scene/scene_string_names.h" -#include "servers/rendering_server.h" -Mutex CanvasItemMaterial::material_mutex; -SelfList<CanvasItemMaterial>::List *CanvasItemMaterial::dirty_materials = nullptr; -Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map; -CanvasItemMaterial::ShaderNames *CanvasItemMaterial::shader_names = nullptr; - -void CanvasItemMaterial::init_shaders() { - dirty_materials = memnew(SelfList<CanvasItemMaterial>::List); - - shader_names = memnew(ShaderNames); - - shader_names->particles_anim_h_frames = "particles_anim_h_frames"; - shader_names->particles_anim_v_frames = "particles_anim_v_frames"; - shader_names->particles_anim_loop = "particles_anim_loop"; -} - -void CanvasItemMaterial::finish_shaders() { - memdelete(dirty_materials); - memdelete(shader_names); - dirty_materials = nullptr; -} - -void CanvasItemMaterial::_update_shader() { - dirty_materials->remove(&element); - - MaterialKey mk = _compute_key(); - if (mk.key == current_key.key) { - return; //no update required in the end - } - - if (shader_map.has(current_key)) { - shader_map[current_key].users--; - if (shader_map[current_key].users == 0) { - //deallocate shader, as it's no longer in use - RS::get_singleton()->free(shader_map[current_key].shader); - shader_map.erase(current_key); - } - } - - current_key = mk; - - if (shader_map.has(mk)) { - RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader); - shader_map[mk].users++; - return; - } - - //must create a shader! - - String code = "shader_type canvas_item;\nrender_mode "; - switch (blend_mode) { - case BLEND_MODE_MIX: - code += "blend_mix"; - break; - case BLEND_MODE_ADD: - code += "blend_add"; - break; - case BLEND_MODE_SUB: - code += "blend_sub"; - break; - case BLEND_MODE_MUL: - code += "blend_mul"; - break; - case BLEND_MODE_PREMULT_ALPHA: - code += "blend_premul_alpha"; - break; - case BLEND_MODE_DISABLED: - code += "blend_disabled"; - break; - } - - switch (light_mode) { - case LIGHT_MODE_NORMAL: - break; - case LIGHT_MODE_UNSHADED: - code += ",unshaded"; - break; - case LIGHT_MODE_LIGHT_ONLY: - code += ",light_only"; - break; - } - - code += ";\n"; - - if (particles_animation) { - code += "uniform int particles_anim_h_frames;\n"; - code += "uniform int particles_anim_v_frames;\n"; - code += "uniform bool particles_anim_loop;\n"; - - code += "void vertex() {\n"; - - code += "\tfloat h_frames = float(particles_anim_h_frames);\n"; - code += "\tfloat v_frames = float(particles_anim_v_frames);\n"; - - code += "\tVERTEX.xy /= vec2(h_frames, v_frames);\n"; - - code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n"; - code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n"; - code += "\tif (!particles_anim_loop) {\n"; - code += "\t\tparticle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n"; - code += "\t} else {\n"; - code += "\t\tparticle_frame = mod(particle_frame, particle_total_frames);\n"; - code += "\t}"; - code += "\tUV /= vec2(h_frames, v_frames);\n"; - code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n"; - code += "}\n"; - } - - ShaderData shader_data; - shader_data.shader = RS::get_singleton()->shader_create(); - shader_data.users = 1; - - RS::get_singleton()->shader_set_code(shader_data.shader, code); - - shader_map[mk] = shader_data; - - RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader); -} - -void CanvasItemMaterial::flush_changes() { - MutexLock lock(material_mutex); - - while (dirty_materials->first()) { - dirty_materials->first()->self()->_update_shader(); - } -} - -void CanvasItemMaterial::_queue_shader_change() { - MutexLock lock(material_mutex); - - if (!element.in_list()) { - dirty_materials->add(&element); - } -} - -bool CanvasItemMaterial::_is_shader_dirty() const { - MutexLock lock(material_mutex); - - return element.in_list(); -} - -void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) { - blend_mode = p_blend_mode; - _queue_shader_change(); -} - -CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const { - return blend_mode; -} - -void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) { - light_mode = p_light_mode; - _queue_shader_change(); -} - -CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const { - return light_mode; -} - -void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) { - particles_animation = p_particles_anim; - _queue_shader_change(); - notify_property_list_changed(); -} - -bool CanvasItemMaterial::get_particles_animation() const { - return particles_animation; -} - -void CanvasItemMaterial::set_particles_anim_h_frames(int p_frames) { - particles_anim_h_frames = p_frames; - RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames); -} - -int CanvasItemMaterial::get_particles_anim_h_frames() const { - return particles_anim_h_frames; -} - -void CanvasItemMaterial::set_particles_anim_v_frames(int p_frames) { - particles_anim_v_frames = p_frames; - RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames); -} - -int CanvasItemMaterial::get_particles_anim_v_frames() const { - return particles_anim_v_frames; -} - -void CanvasItemMaterial::set_particles_anim_loop(bool p_loop) { - particles_anim_loop = p_loop; - RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop); -} - -bool CanvasItemMaterial::get_particles_anim_loop() const { - return particles_anim_loop; -} - -void CanvasItemMaterial::_validate_property(PropertyInfo &property) const { - if (property.name.begins_with("particles_anim_") && !particles_animation) { - property.usage = PROPERTY_USAGE_NONE; - } -} - -RID CanvasItemMaterial::get_shader_rid() const { - ERR_FAIL_COND_V(!shader_map.has(current_key), RID()); - return shader_map[current_key].shader; -} - -Shader::Mode CanvasItemMaterial::get_shader_mode() const { - return Shader::MODE_CANVAS_ITEM; -} - -void CanvasItemMaterial::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode); - ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode); - - ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode); - ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode); - - ClassDB::bind_method(D_METHOD("set_particles_animation", "particles_anim"), &CanvasItemMaterial::set_particles_animation); - ClassDB::bind_method(D_METHOD("get_particles_animation"), &CanvasItemMaterial::get_particles_animation); - - ClassDB::bind_method(D_METHOD("set_particles_anim_h_frames", "frames"), &CanvasItemMaterial::set_particles_anim_h_frames); - ClassDB::bind_method(D_METHOD("get_particles_anim_h_frames"), &CanvasItemMaterial::get_particles_anim_h_frames); - - ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &CanvasItemMaterial::set_particles_anim_v_frames); - ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &CanvasItemMaterial::get_particles_anim_v_frames); - - ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &CanvasItemMaterial::set_particles_anim_loop); - ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &CanvasItemMaterial::get_particles_anim_loop); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Subtract,Multiply,Premultiplied Alpha"), "set_blend_mode", "get_blend_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_animation"), "set_particles_animation", "get_particles_animation"); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_h_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_h_frames", "get_particles_anim_h_frames"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_v_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_v_frames", "get_particles_anim_v_frames"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_anim_loop"), "set_particles_anim_loop", "get_particles_anim_loop"); - - BIND_ENUM_CONSTANT(BLEND_MODE_MIX); - BIND_ENUM_CONSTANT(BLEND_MODE_ADD); - BIND_ENUM_CONSTANT(BLEND_MODE_SUB); - BIND_ENUM_CONSTANT(BLEND_MODE_MUL); - BIND_ENUM_CONSTANT(BLEND_MODE_PREMULT_ALPHA); - - BIND_ENUM_CONSTANT(LIGHT_MODE_NORMAL); - BIND_ENUM_CONSTANT(LIGHT_MODE_UNSHADED); - BIND_ENUM_CONSTANT(LIGHT_MODE_LIGHT_ONLY); -} - -CanvasItemMaterial::CanvasItemMaterial() : - element(this) { - set_particles_anim_h_frames(1); - set_particles_anim_v_frames(1); - set_particles_anim_loop(false); - - current_key.invalid_key = 1; - _queue_shader_change(); -} - -CanvasItemMaterial::~CanvasItemMaterial() { - MutexLock lock(material_mutex); - - if (shader_map.has(current_key)) { - shader_map[current_key].users--; - if (shader_map[current_key].users == 0) { - //deallocate shader, as it's no longer in use - RS::get_singleton()->free(shader_map[current_key].shader); - shader_map.erase(current_key); - } - - RS::get_singleton()->material_set_shader(_get_material(), RID()); - } -} - -/////////////////////////////////////////////////////////////////// #ifdef TOOLS_ENABLED bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { if (_edit_use_rect()) { @@ -426,9 +151,7 @@ void CanvasItem::_update_callback() { current_item_drawn = this; notification(NOTIFICATION_DRAW); emit_signal(SceneStringNames::get_singleton()->draw); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_draw); - } + GDVIRTUAL_CALL(_draw); current_item_drawn = nullptr; drawing = false; } @@ -526,7 +249,7 @@ void CanvasItem::_enter_canvas() { get_viewport()->gui_reset_canvas_sort_index(); } - get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_top_level_raise_self"); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, SNAME("_top_level_raise_self")); } else { CanvasItem *parent = get_parent_item(); @@ -545,7 +268,7 @@ void CanvasItem::_exit_canvas() { notification(NOTIFICATION_EXIT_CANVAS, true); //reverse the notification RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, RID()); canvas_layer = nullptr; - group = ""; + group = StringName(); } void CanvasItem::_notification(int p_what) { @@ -591,7 +314,7 @@ void CanvasItem::_notification(int p_what) { break; } - if (group != "") { + if (group != StringName()) { get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_top_level_raise_self"); } else { CanvasItem *p = get_parent_item(); @@ -651,7 +374,7 @@ void CanvasItem::update() { pending_update = true; - MessageQueue::get_singleton()->push_call(this, "_update_callback"); + MessageQueue::get_singleton()->push_call(this, SNAME("_update_callback")); } void CanvasItem::set_modulate(const Color &p_modulate) { @@ -848,6 +571,12 @@ void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv); } +void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range) { + ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL_COND(p_texture.is_null()); + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range); +} + void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); @@ -959,8 +688,7 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) { } } - for (List<CanvasItem *>::Element *E = p_node->children_items.front(); E; E = E->next()) { - CanvasItem *ci = E->get(); + for (CanvasItem *ci : p_node->children_items) { if (ci->top_level) { continue; } @@ -1159,6 +887,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0)); ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box); ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>())); @@ -1210,7 +939,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children); ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children); - BIND_VMETHOD(MethodInfo("_draw")); + GDVIRTUAL_BIND(_draw); ADD_GROUP("Visibility", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); @@ -1227,7 +956,7 @@ void CanvasItem::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat"); ADD_GROUP("Material", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial"), "set_material", "get_material"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material"); // ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled"); @@ -1337,9 +1066,9 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) { update(); if (p_propagate) { - for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) { - if (!E->get()->top_level && E->get()->texture_filter == TEXTURE_FILTER_PARENT_NODE) { - E->get()->_update_texture_filter_changed(true); + for (CanvasItem *E : children_items) { + if (!E->top_level && E->texture_filter == TEXTURE_FILTER_PARENT_NODE) { + E->_update_texture_filter_changed(true); } } } @@ -1377,9 +1106,9 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) { RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache); update(); if (p_propagate) { - for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) { - if (!E->get()->top_level && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) { - E->get()->_update_texture_repeat_changed(true); + for (CanvasItem *E : children_items) { + if (!E->top_level && E->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) { + E->_update_texture_repeat_changed(true); } } } diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index afdd18d76b..01ed47d4dc 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -33,132 +33,15 @@ #include "scene/main/node.h" #include "scene/main/scene_tree.h" -#include "scene/resources/material.h" -#include "scene/resources/multimesh.h" -#include "scene/resources/shader.h" -#include "scene/resources/texture.h" +#include "scene/resources/canvas_item_material.h" #include "servers/text_server.h" class CanvasLayer; -class Viewport; class Font; - +class MultiMesh; class StyleBox; - -class CanvasItemMaterial : public Material { - GDCLASS(CanvasItemMaterial, Material); - -public: - enum BlendMode { - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - BLEND_MODE_PREMULT_ALPHA, - BLEND_MODE_DISABLED - }; - - enum LightMode { - LIGHT_MODE_NORMAL, - LIGHT_MODE_UNSHADED, - LIGHT_MODE_LIGHT_ONLY - }; - -private: - union MaterialKey { - struct { - uint32_t blend_mode : 4; - uint32_t light_mode : 4; - uint32_t particles_animation : 1; - uint32_t invalid_key : 1; - }; - - uint32_t key = 0; - - bool operator<(const MaterialKey &p_key) const { - return key < p_key.key; - } - }; - - struct ShaderNames { - StringName particles_anim_h_frames; - StringName particles_anim_v_frames; - StringName particles_anim_loop; - }; - - static ShaderNames *shader_names; - - struct ShaderData { - RID shader; - int users = 0; - }; - - static Map<MaterialKey, ShaderData> shader_map; - - MaterialKey current_key; - - _FORCE_INLINE_ MaterialKey _compute_key() const { - MaterialKey mk; - mk.key = 0; - mk.blend_mode = blend_mode; - mk.light_mode = light_mode; - mk.particles_animation = particles_animation; - return mk; - } - - static Mutex material_mutex; - static SelfList<CanvasItemMaterial>::List *dirty_materials; - SelfList<CanvasItemMaterial> element; - - void _update_shader(); - _FORCE_INLINE_ void _queue_shader_change(); - _FORCE_INLINE_ bool _is_shader_dirty() const; - - BlendMode blend_mode = BLEND_MODE_MIX; - LightMode light_mode = LIGHT_MODE_NORMAL; - bool particles_animation = false; - - // Initialized in the constructor. - int particles_anim_h_frames; - int particles_anim_v_frames; - bool particles_anim_loop; - -protected: - static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; - -public: - void set_blend_mode(BlendMode p_blend_mode); - BlendMode get_blend_mode() const; - - void set_light_mode(LightMode p_light_mode); - LightMode get_light_mode() const; - - void set_particles_animation(bool p_particles_anim); - bool get_particles_animation() const; - - void set_particles_anim_h_frames(int p_frames); - int get_particles_anim_h_frames() const; - void set_particles_anim_v_frames(int p_frames); - int get_particles_anim_v_frames() const; - - void set_particles_anim_loop(bool p_loop); - bool get_particles_anim_loop() const; - - static void init_shaders(); - static void finish_shaders(); - static void flush_changes(); - - virtual RID get_shader_rid() const override; - - virtual Shader::Mode get_shader_mode() const override; - - CanvasItemMaterial(); - virtual ~CanvasItemMaterial(); -}; - -VARIANT_ENUM_CAST(CanvasItemMaterial::BlendMode) -VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode) +class Window; +class World2D; class CanvasItem : public Node { GDCLASS(CanvasItem, Node); @@ -187,7 +70,7 @@ private: mutable SelfList<Node> xform_change; RID canvas_item; - String group; + StringName group; CanvasLayer *canvas_layer = nullptr; @@ -259,6 +142,7 @@ protected: void _notification(int p_what); static void _bind_methods(); + GDVIRTUAL0(_draw) public: enum { NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique @@ -342,6 +226,7 @@ public: void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1)); void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false); + void draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0); void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect); void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), real_t p_width = 1); void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>()); diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 5de1ebf18d..9d8e0c203d 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -32,7 +32,6 @@ #define CANVAS_LAYER_H #include "scene/main/node.h" -#include "scene/resources/world_2d.h" class Viewport; class CanvasLayer : public Node { diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 775dfa4c46..f24d880045 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -30,7 +30,7 @@ #include "http_request.h" #include "core/io/compression.h" -#include "core/string/ustring.h" +#include "scene/main/timer.h" void HTTPRequest::_redirect_request(const String &p_new_url) { } @@ -151,7 +151,7 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust client->set_blocking_mode(false); err = _request(); if (err != OK) { - call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); return ERR_CANT_CONNECT; } @@ -167,7 +167,7 @@ void HTTPRequest::_thread_func(void *p_userdata) { Error err = hr->_request(); if (err != OK) { - hr->call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); + hr->call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); } else { while (!hr->thread_request_quit.is_set()) { bool exit = hr->_update_connection(); @@ -209,7 +209,7 @@ void HTTPRequest::cancel_request() { bool HTTPRequest::_handle_response(bool *ret_value) { if (!client->has_response()) { - call_deferred("_request_done", RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray()); *ret_value = true; return true; } @@ -220,24 +220,24 @@ bool HTTPRequest::_handle_response(bool *ret_value) { client->get_response_headers(&rheaders); response_headers.resize(0); downloaded.set(0); - for (List<String>::Element *E = rheaders.front(); E; E = E->next()) { - response_headers.push_back(E->get()); + for (const String &E : rheaders) { + response_headers.push_back(E); } if (response_code == 301 || response_code == 302) { // Handle redirect if (max_redirects >= 0 && redirections >= max_redirects) { - call_deferred("_request_done", RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray()); *ret_value = true; return true; } String new_request; - for (List<String>::Element *E = rheaders.front(); E; E = E->next()) { - if (E->get().findn("Location: ") != -1) { - new_request = E->get().substr(9, E->get().length()).strip_edges(); + for (const String &E : rheaders) { + if (E.findn("Location: ") != -1) { + new_request = E.substr(9, E.length()).strip_edges(); } } @@ -273,7 +273,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) { bool HTTPRequest::_update_connection() { switch (client->get_status()) { case HTTPClient::STATUS_DISCONNECTED: { - call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); return true; // End it, since it's doing something } break; case HTTPClient::STATUS_RESOLVING: { @@ -282,7 +282,7 @@ bool HTTPRequest::_update_connection() { return false; } break; case HTTPClient::STATUS_CANT_RESOLVE: { - call_deferred("_request_done", RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray()); return true; } break; @@ -292,7 +292,7 @@ bool HTTPRequest::_update_connection() { return false; } break; // Connecting to IP case HTTPClient::STATUS_CANT_CONNECT: { - call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); return true; } break; @@ -307,16 +307,16 @@ bool HTTPRequest::_update_connection() { return ret_value; } - call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray()); return true; } if (body_len < 0) { // Chunked transfer is done - call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); + call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body); return true; } - call_deferred("_request_done", RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray()); return true; // Request might have been done } else { @@ -325,7 +325,7 @@ bool HTTPRequest::_update_connection() { int size = request_data.size(); Error err = client->request(method, request_string, headers, size > 0 ? request_data.ptr() : nullptr, size); if (err != OK) { - call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; } @@ -348,7 +348,7 @@ bool HTTPRequest::_update_connection() { } if (!client->is_response_chunked() && client->get_response_body_length() == 0) { - call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray()); return true; } @@ -357,14 +357,14 @@ bool HTTPRequest::_update_connection() { body_len = client->get_response_body_length(); if (body_size_limit >= 0 && body_len > body_size_limit) { - call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); return true; } if (download_to_file != String()) { file = FileAccess::open(download_to_file, FileAccess::WRITE); if (!file) { - call_deferred("_request_done", RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray()); return true; } } @@ -383,7 +383,7 @@ bool HTTPRequest::_update_connection() { const uint8_t *r = chunk.ptr(); file->store_buffer(r, chunk.size()); if (file->get_error() != OK) { - call_deferred("_request_done", RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray()); return true; } } else { @@ -392,18 +392,18 @@ bool HTTPRequest::_update_connection() { } if (body_size_limit >= 0 && downloaded.get() > body_size_limit) { - call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); return true; } if (body_len >= 0) { if (downloaded.get() == body_len) { - call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); + call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body); return true; } } else if (client->get_status() == HTTPClient::STATUS_DISCONNECTED) { // We read till EOF, with no errors. Request is done. - call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); + call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body); return true; } @@ -411,11 +411,11 @@ bool HTTPRequest::_update_connection() { } break; // Request resulted in body: break which must be read case HTTPClient::STATUS_CONNECTION_ERROR: { - call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; } break; case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR: { - call_deferred("_request_done", RESULT_SSL_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_SSL_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; } break; } @@ -463,7 +463,7 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra data = &p_data; } - emit_signal("request_completed", p_status, p_code, p_headers, *data); + emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, *data); } void HTTPRequest::_notification(int p_what) { @@ -563,7 +563,7 @@ int HTTPRequest::get_timeout() { void HTTPRequest::_timeout() { cancel_request(); - call_deferred("_request_done", RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray()); + call_deferred(SNAME("_request_done"), RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray()); } void HTTPRequest::_bind_methods() { diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 22e822253f..673cf3a740 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -31,12 +31,12 @@ #ifndef HTTPREQUEST_H #define HTTPREQUEST_H -#include "core/io/file_access.h" #include "core/io/http_client.h" #include "core/os/thread.h" #include "core/templates/safe_refcount.h" -#include "node.h" -#include "scene/main/timer.h" +#include "scene/main/node.h" + +class Timer; class HTTPRequest : public Node { GDCLASS(HTTPRequest, Node); diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp index 89dac5f5a8..b5ba1899ec 100644 --- a/scene/main/instance_placeholder.cpp +++ b/scene/main/instance_placeholder.cpp @@ -42,9 +42,9 @@ bool InstancePlaceholder::_set(const StringName &p_name, const Variant &p_value) } bool InstancePlaceholder::_get(const StringName &p_name, Variant &r_ret) const { - for (const List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) { - if (E->get().name == p_name) { - r_ret = E->get().value; + for (const PropSet &E : stored_values) { + if (E.name == p_name) { + r_ret = E.value; return true; } } @@ -52,10 +52,10 @@ bool InstancePlaceholder::_get(const StringName &p_name, Variant &r_ret) const { } void InstancePlaceholder::_get_property_list(List<PropertyInfo> *p_list) const { - for (const List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) { + for (const PropSet &E : stored_values) { PropertyInfo pi; - pi.name = E->get().name; - pi.type = E->get().value.get_type(); + pi.name = E.name; + pi.type = E.value.get_type(); pi.usage = PROPERTY_USAGE_STORAGE; p_list->push_back(pi); @@ -95,8 +95,8 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene scene->set_name(get_name()); int pos = get_index(); - for (List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) { - scene->set(E->get().name, E->get().value); + for (const PropSet &E : stored_values) { + scene->set(E.name, E.value); } if (p_replace) { @@ -114,10 +114,10 @@ Dictionary InstancePlaceholder::get_stored_values(bool p_with_order) { Dictionary ret; PackedStringArray order; - for (List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) { - ret[E->get().name] = E->get().value; + for (const PropSet &E : stored_values) { + ret[E.name] = E.value; if (p_with_order) { - order.push_back(E->get().name); + order.push_back(E.name); } }; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index ac092d9862..05409b7bfe 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -48,22 +48,18 @@ #include <stdint.h> VARIANT_ENUM_CAST(Node::ProcessMode); +VARIANT_ENUM_CAST(Node::InternalMode); int Node::orphan_node_count = 0; void Node::_notification(int p_notification) { switch (p_notification) { case NOTIFICATION_PROCESS: { - if (get_script_instance()) { - Variant time = get_process_delta_time(); - get_script_instance()->call(SceneStringNames::get_singleton()->_process, time); - } + GDVIRTUAL_CALL(_process, get_process_delta_time()); + } break; case NOTIFICATION_PHYSICS_PROCESS: { - if (get_script_instance()) { - Variant time = get_physics_process_delta_time(); - get_script_instance()->call(SceneStringNames::get_singleton()->_physics_process, time); - } + GDVIRTUAL_CALL(_physics_process, get_physics_process_delta_time()); } break; case NOTIFICATION_ENTER_TREE: { @@ -116,6 +112,9 @@ void Node::_notification(int p_notification) { memdelete(data.path_cache); data.path_cache = nullptr; } + if (data.filename.length()) { + get_multiplayer()->scene_enter_exit_notify(data.filename, this, false); + } } break; case NOTIFICATION_PATH_CHANGED: { if (data.path_cache) { @@ -124,28 +123,30 @@ void Node::_notification(int p_notification) { } } break; case NOTIFICATION_READY: { - if (get_script_instance()) { - if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_input)) { - set_process_input(true); - } + if (GDVIRTUAL_IS_OVERRIDDEN(_input)) { + set_process_input(true); + } - if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_unhandled_input)) { - set_process_unhandled_input(true); - } + if (GDVIRTUAL_IS_OVERRIDDEN(_unhandled_input)) { + set_process_unhandled_input(true); + } - if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_unhandled_key_input)) { - set_process_unhandled_key_input(true); - } + if (GDVIRTUAL_IS_OVERRIDDEN(_unhandled_key_input)) { + set_process_unhandled_key_input(true); + } - if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_process)) { - set_process(true); - } + if (GDVIRTUAL_IS_OVERRIDDEN(_process)) { + set_process(true); + } + if (GDVIRTUAL_IS_OVERRIDDEN(_physics_process)) { + set_physics_process(true); + } - if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_physics_process)) { - set_physics_process(true); - } + GDVIRTUAL_CALL(_ready); - get_script_instance()->call(SceneStringNames::get_singleton()->_ready); + if (data.filename.length()) { + ERR_FAIL_COND(!is_inside_tree()); + get_multiplayer()->scene_enter_exit_notify(data.filename, this, true); } } break; @@ -214,9 +215,7 @@ void Node::_propagate_enter_tree() { notification(NOTIFICATION_ENTER_TREE); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_enter_tree); - } + GDVIRTUAL_CALL(_enter_tree); emit_signal(SceneStringNames::get_singleton()->tree_entered); @@ -262,9 +261,8 @@ void Node::_propagate_exit_tree() { data.blocked--; - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_exit_tree); - } + GDVIRTUAL_CALL(_exit_tree); + emit_signal(SceneStringNames::get_singleton()->tree_exiting); notification(NOTIFICATION_EXIT_TREE, true); @@ -293,14 +291,40 @@ void Node::_propagate_exit_tree() { void Node::move_child(Node *p_child, int p_pos) { ERR_FAIL_NULL(p_child); - ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1, vformat("Invalid new child position: %d.", p_pos)); 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()) { + 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); + } else if (p_child->_is_internal_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); + } else { + 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); + } +} + +void Node::_move_child(Node *p_child, int p_pos, 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 - if (p_pos == data.children.size()) { - p_pos--; + 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--; + } + } else if (p_child->_is_internal_back()) { + if (p_pos == data.children.size()) { + p_pos--; + } + } else { + if (p_pos == data.children.size() - data.internal_children_back) { + p_pos--; + } + } } if (p_child->data.pos == p_pos) { @@ -341,7 +365,14 @@ void Node::raise() { return; } - data.parent->move_child(this, data.parent->data.children.size() - 1); + // Internal children move within a different index range. + if (_is_internal_front()) { + data.parent->move_child(this, data.parent->data.internal_children_front - 1); + } else if (_is_internal_back()) { + data.parent->move_child(this, data.parent->data.internal_children_back - 1); + } else { + data.parent->move_child(this, data.parent->get_child_count(false) - 1); + } } void Node::add_child_notify(Node *p_child) { @@ -442,7 +473,7 @@ void Node::set_process_mode(ProcessMode p_mode) { // This is required for the editor to update the visibility of disabled nodes // It's very expensive during runtime to change, so editor-only if (Engine::get_singleton()->is_editor_hint()) { - get_tree()->emit_signal("tree_process_mode_changed"); + get_tree()->emit_signal(SNAME("tree_process_mode_changed")); } #endif } @@ -485,32 +516,32 @@ void Node::_propagate_process_owner(Node *p_owner, int p_pause_notification, int } } -void Node::set_network_master(int p_peer_id, bool p_recursive) { - data.network_master = p_peer_id; +void Node::set_multiplayer_authority(int p_peer_id, bool p_recursive) { + data.multiplayer_authority = p_peer_id; if (p_recursive) { for (int i = 0; i < data.children.size(); i++) { - data.children[i]->set_network_master(p_peer_id, true); + data.children[i]->set_multiplayer_authority(p_peer_id, true); } } } -int Node::get_network_master() const { - return data.network_master; +int Node::get_multiplayer_authority() const { + return data.multiplayer_authority; } -bool Node::is_network_master() const { +bool Node::is_multiplayer_authority() const { ERR_FAIL_COND_V(!is_inside_tree(), false); - return get_multiplayer()->get_network_unique_id() == data.network_master; + return get_multiplayer()->get_unique_id() == data.multiplayer_authority; } /***** RPC CONFIG ********/ -uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, NetworkedMultiplayerPeer::TransferMode p_transfer_mode, int p_channel) { +uint16_t Node::rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc_mode, Multiplayer::TransferMode p_transfer_mode, int p_channel) { for (int i = 0; i < data.rpc_methods.size(); i++) { if (data.rpc_methods[i].name == p_method) { - MultiplayerAPI::RPCConfig &nd = data.rpc_methods.write[i]; + Multiplayer::RPCConfig &nd = data.rpc_methods.write[i]; nd.rpc_mode = p_rpc_mode; nd.transfer_mode = p_transfer_mode; nd.channel = p_channel; @@ -518,7 +549,7 @@ uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_ } } // New method - MultiplayerAPI::RPCConfig nd; + Multiplayer::RPCConfig nd; nd.name = p_method; nd.rpc_mode = p_rpc_mode; nd.transfer_mode = p_transfer_mode; @@ -611,7 +642,7 @@ Variant Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::Cal void Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND(!is_inside_tree()); - get_multiplayer()->rpcp(this, p_peer_id, true, p_method, p_arg, p_argcount); + get_multiplayer()->rpcp(this, p_peer_id, p_method, p_arg, p_argcount); } Ref<MultiplayerAPI> Node::get_multiplayer() const { @@ -632,7 +663,7 @@ void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) { multiplayer = p_multiplayer; } -Vector<MultiplayerAPI::RPCConfig> Node::get_node_rpc_methods() const { +Vector<Multiplayer::RPCConfig> Node::get_node_rpc_methods() const { return data.rpc_methods; } @@ -705,7 +736,7 @@ bool Node::is_enabled() const { return _is_enabled(); } -float Node::get_physics_process_delta_time() const { +double Node::get_physics_process_delta_time() const { if (data.tree) { return data.tree->get_physics_process_time(); } else { @@ -713,7 +744,7 @@ float Node::get_physics_process_delta_time() const { } } -float Node::get_process_delta_time() const { +double Node::get_process_delta_time() const { if (data.tree) { return data.tree->get_process_time(); } else { @@ -868,7 +899,7 @@ void Node::set_name(const String &p_name) { propagate_notification(NOTIFICATION_PATH_CHANGED); if (is_inside_tree()) { - emit_signal("renamed"); + emit_signal(SNAME("renamed")); get_tree()->node_renamed(this); get_tree()->tree_changed(); } @@ -1060,6 +1091,10 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) { p_child->data.pos = data.children.size(); data.children.push_back(p_child); p_child->data.parent = this; + + if (data.internal_children_back > 0) { + _move_child(p_child, data.children.size() - data.internal_children_back - 1); + } p_child->notification(NOTIFICATION_PARENTED); if (data.tree) { @@ -1072,7 +1107,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) { add_child_notify(p_child); } -void Node::add_child(Node *p_child, bool p_legible_unique_name) { +void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_internal) { ERR_FAIL_NULL(p_child); ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name())); // adding to itself! ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent @@ -1081,19 +1116,35 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name) { #endif ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead."); - /* Validate name */ _validate_child_name(p_child, p_legible_unique_name); - _add_child_nocheck(p_child, p_child->data.name); + + if (p_internal == INTERNAL_MODE_FRONT) { + _move_child(p_child, data.internal_children_front); + data.internal_children_front++; + } else if (p_internal == INTERNAL_MODE_BACK) { + if (data.internal_children_back > 0) { + _move_child(p_child, data.children.size() - 1, true); + } + data.internal_children_back++; + } } void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) { ERR_FAIL_NULL(p_sibling); + ERR_FAIL_NULL(data.parent); ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself! ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_sibling() failed. Consider using call_deferred(\"add_sibling\", sibling) instead."); - get_parent()->add_child(p_sibling, p_legible_unique_name); - get_parent()->move_child(p_sibling, this->get_index() + 1); + InternalMode internal = INTERNAL_MODE_DISABLED; + if (_is_internal_front()) { // The sibling will have the same internal status. + internal = INTERNAL_MODE_FRONT; + } else if (_is_internal_back()) { + internal = INTERNAL_MODE_BACK; + } + + data.parent->add_child(p_sibling, p_legible_unique_name, internal); + data.parent->_move_child(p_sibling, get_index() + 1); } void Node::_propagate_validate_owner() { @@ -1147,7 +1198,12 @@ void Node::remove_child(Node *p_child) { ERR_FAIL_COND_MSG(idx == -1, vformat("Cannot remove child node '%s' as it is not a child of this node.", p_child->get_name())); //ERR_FAIL_COND( p_child->data.blocked > 0 ); - //if (data.scene) { does not matter + // If internal child, update the counter. + if (p_child->_is_internal_front()) { + data.internal_children_front--; + } else if (p_child->_is_internal_back()) { + data.internal_children_back--; + } p_child->_set_tree(nullptr); //} @@ -1177,17 +1233,29 @@ void Node::remove_child(Node *p_child) { } } -int Node::get_child_count() const { - return data.children.size(); +int Node::get_child_count(bool p_include_internal) const { + if (p_include_internal) { + return data.children.size(); + } else { + return data.children.size() - data.internal_children_front - data.internal_children_back; + } } -Node *Node::get_child(int p_index) const { - if (p_index < 0) { - p_index += data.children.size(); +Node *Node::get_child(int p_index, bool p_include_internal) const { + if (p_include_internal) { + if (p_index < 0) { + p_index += data.children.size(); + } + ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr); + return data.children[p_index]; + } else { + if (p_index < 0) { + p_index += data.children.size() - data.internal_children_front - data.internal_children_back; + } + ERR_FAIL_INDEX_V(p_index, data.children.size() - data.internal_children_front - data.internal_children_back, nullptr); + p_index += data.internal_children_front; + return data.children[p_index]; } - ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr); - - return data.children[p_index]; } Node *Node::_get_child_by_name(const StringName &p_name) const { @@ -1597,8 +1665,8 @@ Array Node::_get_groups() const { Array groups; List<GroupInfo> gi; get_groups(&gi); - for (List<GroupInfo>::Element *E = gi.front(); E; E = E->next()) { - groups.push_back(E->get().name); + for (const GroupInfo &E : gi) { + groups.push_back(E.name); } return groups; @@ -1719,7 +1787,13 @@ void Node::_propagate_replace_owner(Node *p_owner, Node *p_by_owner) { data.blocked--; } -int Node::get_index() const { +int Node::get_index(bool p_include_internal) const { + // p_include_internal = false doesn't make sense if the node is internal. + 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.pos; } @@ -1822,6 +1896,18 @@ Node *Node::get_deepest_editable_node(Node *p_start_node) const { return node; } +String Node::to_string() { + if (get_script_instance()) { + bool valid; + String ret = get_script_instance()->to_string(&valid); + if (valid) { + return ret; + } + } + + return (get_name() ? String(get_name()) + ":" : "") + Object::to_string(); +} + void Node::set_scene_instance_state(const Ref<SceneState> &p_state) { data.instance_state = p_state; } @@ -1935,18 +2021,18 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const List<PropertyInfo> plist; N->get()->get_property_list(&plist); - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { + for (const PropertyInfo &E : plist) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { continue; } - String name = E->get().name; + String name = E.name; if (name == script_property_name) { continue; } Variant value = N->get()->get(name).duplicate(true); - if (E->get().usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE) { + if (E.usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE) { Resource *res = Object::cast_to<Resource>(value); if (res) { // Duplicate only if it's a resource current_node->set(name, res->duplicate()); @@ -1971,14 +2057,14 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const if (p_flags & DUPLICATE_GROUPS) { List<GroupInfo> gi; get_groups(&gi); - for (List<GroupInfo>::Element *E = gi.front(); E; E = E->next()) { + for (const GroupInfo &E : gi) { #ifdef TOOLS_ENABLED - if ((p_flags & DUPLICATE_FROM_EDITOR) && !E->get().persistent) { + if ((p_flags & DUPLICATE_FROM_EDITOR) && !E.persistent) { continue; } #endif - node->add_to_group(E->get().name, E->get().persistent); + node->add_to_group(E.name, E.persistent); } } @@ -2002,21 +2088,21 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const } } - for (List<const Node *>::Element *E = hidden_roots.front(); E; E = E->next()) { - Node *parent = node->get_node(get_path_to(E->get()->data.parent)); + for (const Node *&E : hidden_roots) { + Node *parent = node->get_node(get_path_to(E->data.parent)); if (!parent) { memdelete(node); return nullptr; } - Node *dup = E->get()->_duplicate(p_flags, r_duplimap); + Node *dup = E->_duplicate(p_flags, r_duplimap); if (!dup) { memdelete(node); return nullptr; } parent->add_child(dup); - int pos = E->get()->get_index(); + int pos = E->get_index(); if (pos < parent->get_child_count() - 1) { parent->move_child(dup, pos); @@ -2061,17 +2147,17 @@ void Node::remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_re List<PropertyInfo> props; p_node->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { + for (const PropertyInfo &E : props) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { continue; } - Variant v = p_node->get(E->get().name); + Variant v = p_node->get(E.name); if (v.is_ref()) { RES res = v; if (res.is_valid()) { if (p_resource_remap.has(res)) { - p_node->set(E->get().name, p_resource_remap[res]); + p_node->set(E.name, p_resource_remap[res]); remap_nested_resources(res, p_resource_remap); } } @@ -2087,17 +2173,17 @@ void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resourc List<PropertyInfo> props; p_resource->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { + for (const PropertyInfo &E : props) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { continue; } - Variant v = p_resource->get(E->get().name); + Variant v = p_resource->get(E.name); if (v.is_ref()) { RES res = v; if (res.is_valid()) { if (p_resource_remap.has(res)) { - p_resource->set(E->get().name, p_resource_remap[res]); + p_resource->set(E.name, p_resource_remap[res]); remap_nested_resources(res, p_resource_remap); } } @@ -2123,13 +2209,13 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const { List<Connection> conns; n->get_all_signal_connections(&conns); - for (List<Connection>::Element *E = conns.front(); E; E = E->next()) { - if (E->get().flags & CONNECT_PERSIST) { + for (const Connection &E : conns) { + if (E.flags & CONNECT_PERSIST) { //user connected NodePath p = p_original->get_path_to(n); Node *copy = p_copy->get_node(p); - Node *target = Object::cast_to<Node>(E->get().callable.get_object()); + Node *target = Object::cast_to<Node>(E.callable.get_object()); if (!target) { continue; } @@ -2146,9 +2232,9 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const { } if (copy && copytarget) { - const Callable copy_callable = Callable(copytarget, E->get().callable.get_method()); - if (!copy->is_connected(E->get().signal.get_name(), copy_callable)) { - copy->connect(E->get().signal.get_name(), copy_callable, E->get().binds, E->get().flags); + const Callable copy_callable = Callable(copytarget, E.callable.get_method()); + if (!copy->is_connected(E.signal.get_name(), copy_callable)) { + copy->connect(E.signal.get_name(), copy_callable, E.binds, E.flags); } } } @@ -2182,8 +2268,8 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) { List<GroupInfo> groups; get_groups(&groups); - for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next()) { - p_node->add_to_group(E->get().name, E->get().persistent); + for (const GroupInfo &E : groups) { + p_node->add_to_group(E.name, E.persistent); } } @@ -2229,9 +2315,7 @@ void Node::_replace_connections_target(Node *p_new_target) { List<Connection> cl; get_signals_connected_to_this(&cl); - for (List<Connection>::Element *E = cl.front(); E; E = E->next()) { - Connection &c = E->get(); - + for (const Connection &c : cl) { if (c.flags & CONNECT_PERSIST) { c.signal.get_object()->disconnect(c.signal.get_name(), Callable(this, c.callable.get_method())); bool valid = p_new_target->has_method(c.callable.get_method()) || Ref<Script>(p_new_target->get_script()).is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.callable.get_method()); @@ -2421,12 +2505,12 @@ void Node::queue_delete() { } } -TypedArray<Node> Node::_get_children() const { +TypedArray<Node> Node::_get_children(bool p_include_internal) const { TypedArray<Node> arr; - int cc = get_child_count(); + int cc = get_child_count(p_include_internal); arr.resize(cc); for (int i = 0; i < cc; i++) { - arr[i] = get_child(i); + arr[i] = get_child(i, p_include_internal); } return arr; @@ -2448,7 +2532,7 @@ NodePath Node::get_import_path() const { static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<String> *r_options) { #ifdef TOOLS_ENABLED - const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\""; + const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; #else const String quote_style = "\""; #endif @@ -2457,7 +2541,7 @@ static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<S return; } String n = p_base->get_path_to(p_node); - r_options->push_back(quote_style + n + quote_style); + r_options->push_back(n.quote(quote_style)); for (int i = 0; i < p_node->get_child_count(); i++) { _add_nodes_to_options(p_base, p_node->get_child(i), r_options); } @@ -2479,9 +2563,14 @@ void Node::clear_internal_tree_resource_paths() { } TypedArray<String> Node::get_configuration_warnings() const { - if (get_script_instance() && get_script_instance()->get_script().is_valid() && - get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warnings")) { - return get_script_instance()->call("_get_configuration_warnings"); + Vector<String> warnings; + if (GDVIRTUAL_CALL(_get_configuration_warnings, warnings)) { + TypedArray<String> ret; + ret.resize(warnings.size()); + for (int i = 0; i < warnings.size(); i++) { + ret[i] = warnings[i]; + } + return ret; } return Array(); } @@ -2493,7 +2582,9 @@ String Node::get_configuration_warnings_as_string() const { if (i > 0) { all_warnings += "\n\n"; } - all_warnings += String(warnings[i]); + // Format as a bullet point list to make multiple warnings easier to distinguish + // from each other. + all_warnings += String::utf8("• ") + String(warnings[i]); } return all_warnings; } @@ -2525,6 +2616,37 @@ void Node::request_ready() { data.ready_first = true; } +void Node::_call_input(const Ref<InputEvent> &p_event) { + GDVIRTUAL_CALL(_input, p_event); + if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) { + return; + } + input(p_event); +} +void Node::_call_unhandled_input(const Ref<InputEvent> &p_event) { + GDVIRTUAL_CALL(_unhandled_input, p_event); + if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) { + return; + } + unhandled_input(p_event); +} +void Node::_call_unhandled_key_input(const Ref<InputEvent> &p_event) { + GDVIRTUAL_CALL(_unhandled_key_input, p_event); + if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) { + return; + } + unhandled_key_input(p_event); +} + +void Node::input(const Ref<InputEvent> &p_event) { +} + +void Node::unhandled_input(const Ref<InputEvent> &p_event) { +} + +void Node::unhandled_key_input(const Ref<InputEvent> &p_key_event) { +} + void Node::_bind_methods() { GLOBAL_DEF("editor/node_naming/name_num_separator", 0); ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_num_separator", PropertyInfo(Variant::INT, "editor/node_naming/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash")); @@ -2535,11 +2657,11 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("set_name", "name"), &Node::set_name); ClassDB::bind_method(D_METHOD("get_name"), &Node::get_name); - ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name"), &Node::add_child, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0)); ClassDB::bind_method(D_METHOD("remove_child", "node"), &Node::remove_child); - ClassDB::bind_method(D_METHOD("get_child_count"), &Node::get_child_count); - ClassDB::bind_method(D_METHOD("get_children"), &Node::_get_children); - ClassDB::bind_method(D_METHOD("get_child", "idx"), &Node::get_child); + ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript. + ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::_get_children, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_child", "idx", "include_internal"), &Node::get_child, DEFVAL(false)); ClassDB::bind_method(D_METHOD("has_node", "path"), &Node::has_node); ClassDB::bind_method(D_METHOD("get_node", "path"), &Node::get_node); ClassDB::bind_method(D_METHOD("get_node_or_null", "path"), &Node::get_node_or_null); @@ -2563,7 +2685,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner); ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner); ClassDB::bind_method(D_METHOD("remove_and_skip"), &Node::remove_and_skip); - ClassDB::bind_method(D_METHOD("get_index"), &Node::get_index); + ClassDB::bind_method(D_METHOD("get_index", "include_internal"), &Node::get_index, DEFVAL(false)); ClassDB::bind_method(D_METHOD("print_tree"), &Node::print_tree); ClassDB::bind_method(D_METHOD("print_tree_pretty"), &Node::print_tree_pretty); ClassDB::bind_method(D_METHOD("set_filename", "filename"), &Node::set_filename); @@ -2606,6 +2728,8 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder); ClassDB::bind_method(D_METHOD("get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder); + ClassDB::bind_method(D_METHOD("set_editable_instance", "node", "is_editable"), &Node::set_editable_instance); + ClassDB::bind_method(D_METHOD("is_editable_instance", "node"), &Node::is_editable_instance); ClassDB::bind_method(D_METHOD("get_viewport"), &Node::get_viewport); @@ -2613,15 +2737,15 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("request_ready"), &Node::request_ready); - ClassDB::bind_method(D_METHOD("set_network_master", "id", "recursive"), &Node::set_network_master, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("get_network_master"), &Node::get_network_master); + ClassDB::bind_method(D_METHOD("set_multiplayer_authority", "id", "recursive"), &Node::set_multiplayer_authority, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("get_multiplayer_authority"), &Node::get_multiplayer_authority); - ClassDB::bind_method(D_METHOD("is_network_master"), &Node::is_network_master); + ClassDB::bind_method(D_METHOD("is_multiplayer_authority"), &Node::is_multiplayer_authority); ClassDB::bind_method(D_METHOD("get_multiplayer"), &Node::get_multiplayer); ClassDB::bind_method(D_METHOD("get_custom_multiplayer"), &Node::get_custom_multiplayer); ClassDB::bind_method(D_METHOD("set_custom_multiplayer", "api"), &Node::set_custom_multiplayer); - ClassDB::bind_method(D_METHOD("rpc_config", "method", "rpc_mode", "transfer_mode", "channel"), &Node::rpc_config, DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("rpc_config", "method", "rpc_mode", "transfer_mode", "channel"), &Node::rpc_config, DEFVAL(Multiplayer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); ClassDB::bind_method(D_METHOD("set_editor_description", "editor_description"), &Node::set_editor_description); ClassDB::bind_method(D_METHOD("get_editor_description"), &Node::get_editor_description); @@ -2699,6 +2823,10 @@ void Node::_bind_methods() { BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS); BIND_ENUM_CONSTANT(DUPLICATE_USE_INSTANCING); + BIND_ENUM_CONSTANT(INTERNAL_MODE_DISABLED); + BIND_ENUM_CONSTANT(INTERNAL_MODE_FRONT); + BIND_ENUM_CONSTANT(INTERNAL_MODE_BACK); + ADD_SIGNAL(MethodInfo("ready")); ADD_SIGNAL(MethodInfo("renamed")); ADD_SIGNAL(MethodInfo("tree_entered")); @@ -2718,15 +2846,15 @@ void Node::_bind_methods() { ADD_GROUP("Editor Description", "editor_"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "set_editor_description", "get_editor_description"); - BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::FLOAT, "delta"))); - BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::FLOAT, "delta"))); - BIND_VMETHOD(MethodInfo("_enter_tree")); - BIND_VMETHOD(MethodInfo("_exit_tree")); - BIND_VMETHOD(MethodInfo("_ready")); - BIND_VMETHOD(MethodInfo("_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); - BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); - BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey"))); - BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, "String"), "_get_configuration_warnings")); + GDVIRTUAL_BIND(_process, "delta"); + GDVIRTUAL_BIND(_physics_process, "delta"); + GDVIRTUAL_BIND(_enter_tree); + GDVIRTUAL_BIND(_exit_tree); + GDVIRTUAL_BIND(_ready); + GDVIRTUAL_BIND(_get_configuration_warnings); + GDVIRTUAL_BIND(_input, "event"); + GDVIRTUAL_BIND(_unhandled_input, "event"); + GDVIRTUAL_BIND(_unhandled_key_input, "event"); } String Node::_get_name_num_separator() { diff --git a/scene/main/node.h b/scene/main/node.h index fc5af43829..198501eeac 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -67,6 +67,18 @@ public: #endif }; + enum NameCasing { + NAME_CASING_PASCAL_CASE, + NAME_CASING_CAMEL_CASE, + NAME_CASING_SNAKE_CASE + }; + + enum InternalMode { + INTERNAL_MODE_DISABLED, + INTERNAL_MODE_FRONT, + INTERNAL_MODE_BACK, + }; + struct Comparator { bool operator()(const Node *p_a, const Node *p_b) const { return p_b->is_greater_than(p_a); } }; @@ -91,6 +103,8 @@ private: Node *parent = nullptr; Node *owner = nullptr; Vector<Node *> children; + int internal_children_front = 0; + int internal_children_back = 0; int pos = -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. @@ -113,8 +127,8 @@ private: ProcessMode process_mode = PROCESS_MODE_INHERIT; Node *process_owner = nullptr; - int network_master = 1; // Server by default. - Vector<MultiplayerAPI::RPCConfig> rpc_methods; + int multiplayer_authority = 1; // Server by default. + Vector<Multiplayer::RPCConfig> rpc_methods; // Variables used to properly sort the node when processing, ignored otherwise. // TODO: Should move all the stuff below to bits. @@ -140,12 +154,6 @@ private: } data; - enum NameCasing { - NAME_CASING_PASCAL_CASE, - NAME_CASING_CAMEL_CASE, - NAME_CASING_SNAKE_CASE - }; - Ref<MultiplayerAPI> multiplayer; void _print_tree_pretty(const String &prefix, const bool last); @@ -172,12 +180,15 @@ private: void _duplicate_signals(const Node *p_original, Node *p_copy) const; Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = nullptr) const; - TypedArray<Node> _get_children() const; + TypedArray<Node> _get_children(bool p_include_internal = true) const; Array _get_groups() const; Variant _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Variant _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; } + friend class SceneTree; void _set_tree(SceneTree *p_tree); @@ -202,11 +213,33 @@ protected: static String _get_name_num_separator(); friend class SceneState; + friend class MultiplayerReplicator; void _add_child_nocheck(Node *p_child, const StringName &p_name); void _set_owner_nocheck(Node *p_owner); void _set_name_nocheck(const StringName &p_name); + //call from SceneTree + void _call_input(const Ref<InputEvent> &p_event); + void _call_unhandled_input(const Ref<InputEvent> &p_event); + void _call_unhandled_key_input(const Ref<InputEvent> &p_event); + +protected: + virtual void input(const Ref<InputEvent> &p_event); + virtual void unhandled_input(const Ref<InputEvent> &p_event); + virtual void unhandled_key_input(const Ref<InputEvent> &p_key_event); + + GDVIRTUAL1(_process, double) + GDVIRTUAL1(_physics_process, double) + GDVIRTUAL0(_enter_tree) + GDVIRTUAL0(_exit_tree) + GDVIRTUAL0(_ready) + GDVIRTUAL0RC(Vector<String>, _get_configuration_warnings) + + GDVIRTUAL1(_input, Ref<InputEvent>) + GDVIRTUAL1(_unhandled_input, Ref<InputEvent>) + GDVIRTUAL1(_unhandled_key_input, Ref<InputEvent>) + public: enum { // you can make your own, but don't use the same numbers as other notifications in other nodes @@ -262,12 +295,12 @@ public: StringName get_name() const; void set_name(const String &p_name); - void add_child(Node *p_child, bool p_legible_unique_name = false); + void add_child(Node *p_child, bool p_legible_unique_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED); void add_sibling(Node *p_sibling, bool p_legible_unique_name = false); void remove_child(Node *p_child); - int get_child_count() const; - Node *get_child(int p_index) const; + int get_child_count(bool p_include_internal = true) const; + Node *get_child(int p_index, bool p_include_internal = true) const; bool has_node(const NodePath &p_path) const; Node *get_node(const NodePath &p_path) const; Node *get_node_or_null(const NodePath &p_path) const; @@ -305,6 +338,7 @@ public: 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 raise(); void set_owner(Node *p_owner); @@ -312,7 +346,7 @@ public: void get_owned_by(Node *p_by, List<Node *> *p_owned); void remove_and_skip(); - int get_index() const; + int get_index(bool p_include_internal = true) const; Ref<Tween> create_tween(); @@ -329,6 +363,8 @@ public: bool is_editable_instance(const Node *p_node) const; Node *get_deepest_editable_node(Node *p_start_node) const; + virtual String to_string() override; + /* NOTIFICATIONS */ void propagate_notification(int p_notification); @@ -337,11 +373,11 @@ public: /* PROCESSING */ void set_physics_process(bool p_process); - float get_physics_process_delta_time() const; + double get_physics_process_delta_time() const; bool is_physics_processing() const; void set_process(bool p_process); - float get_process_delta_time() const; + double get_process_delta_time() const; bool is_processing() const; void set_physics_process_internal(bool p_process_internal); @@ -426,12 +462,12 @@ public: bool is_displayed_folded() const; /* NETWORK */ - void set_network_master(int p_peer_id, bool p_recursive = true); - int get_network_master() const; - bool is_network_master() const; + void set_multiplayer_authority(int p_peer_id, bool p_recursive = true); + int get_multiplayer_authority() const; + bool is_multiplayer_authority() const; - uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, NetworkedMultiplayerPeer::TransferMode p_transfer_mode, int p_channel = 0); // config a local method for RPC - Vector<MultiplayerAPI::RPCConfig> get_node_rpc_methods() const; + uint16_t rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc_mode, Multiplayer::TransferMode p_transfer_mode, int p_channel = 0); // config a local method for RPC + Vector<Multiplayer::RPCConfig> get_node_rpc_methods() const; void rpc(const StringName &p_method, VARIANT_ARG_LIST); // RPC, honors RPCMode, TransferMode, channel void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); // RPC to specific peer(s), honors RPCMode, TransferMode, channel diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 4b52c4e99f..e1b1b356a9 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -66,11 +66,11 @@ void SceneTreeTimer::_bind_methods() { ADD_SIGNAL(MethodInfo("timeout")); } -void SceneTreeTimer::set_time_left(float p_time) { +void SceneTreeTimer::set_time_left(double p_time) { time_left = p_time; } -float SceneTreeTimer::get_time_left() const { +double SceneTreeTimer::get_time_left() const { return time_left; } @@ -82,12 +82,19 @@ bool SceneTreeTimer::is_process_always() { return process_always; } +void SceneTreeTimer::set_ignore_time_scale(bool p_ignore) { + ignore_time_scale = p_ignore; +} + +bool SceneTreeTimer::is_ignore_time_scale() { + return ignore_time_scale; +} + void SceneTreeTimer::release_connections() { List<Connection> connections; get_all_signal_connections(&connections); - for (List<Connection>::Element *E = connections.front(); E; E = E->next()) { - Connection const &connection = E->get(); + for (const Connection &connection : connections) { disconnect(connection.signal.get_name(), connection.callable); } } @@ -169,8 +176,8 @@ void SceneTree::_flush_ugc() { v[i] = E->get()[i]; } - static_assert(VARIANT_ARG_MAX == 5, "This code needs to be updated if VARIANT_ARG_MAX != 5"); - call_group_flags(GROUP_CALL_REALTIME, E->key().group, E->key().call, v[0], v[1], v[2], v[3], v[4]); + static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); + call_group_flags(GROUP_CALL_REALTIME, E->key().group, E->key().call, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); unique_group_calls.erase(E); } @@ -396,7 +403,7 @@ void SceneTree::initialize() { MainLoop::initialize(); } -bool SceneTree::physics_process(float p_time) { +bool SceneTree::physics_process(double p_time) { root_lock++; current_frame++; @@ -406,11 +413,11 @@ bool SceneTree::physics_process(float p_time) { MainLoop::physics_process(p_time); physics_process_time = p_time; - emit_signal("physics_frame"); + emit_signal(SNAME("physics_frame")); - _notify_group_pause("physics_process_internal", Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS); - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_process_picking"); - _notify_group_pause("physics_process", Node::NOTIFICATION_PHYSICS_PROCESS); + _notify_group_pause(SNAME("physics_process_internal"), Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS); + call_group_flags(GROUP_CALL_REALTIME, SNAME("_picking_viewports"), SNAME("_process_picking")); + _notify_group_pause(SNAME("physics_process"), Node::NOTIFICATION_PHYSICS_PROCESS); _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack @@ -425,7 +432,7 @@ bool SceneTree::physics_process(float p_time) { return _quit; } -bool SceneTree::process(float p_time) { +bool SceneTree::process(double p_time) { root_lock++; MainLoop::process(p_time); @@ -436,14 +443,14 @@ bool SceneTree::process(float p_time) { multiplayer->poll(); } - emit_signal("process_frame"); + emit_signal(SNAME("process_frame")); MessageQueue::get_singleton()->flush(); //small little hack flush_transform_notifications(); - _notify_group_pause("process_internal", Node::NOTIFICATION_INTERNAL_PROCESS); - _notify_group_pause("process", Node::NOTIFICATION_PROCESS); + _notify_group_pause(SNAME("process_internal"), Node::NOTIFICATION_INTERNAL_PROCESS); + _notify_group_pause(SNAME("process"), Node::NOTIFICATION_PROCESS); _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack @@ -466,12 +473,17 @@ bool SceneTree::process(float p_time) { E = N; continue; } - float time_left = E->get()->get_time_left(); - time_left -= p_time; + + double time_left = E->get()->get_time_left(); + if (E->get()->is_ignore_time_scale()) { + time_left -= Engine::get_singleton()->get_process_step(); + } else { + time_left -= p_time; + } E->get()->set_time_left(time_left); if (time_left < 0) { - E->get()->emit_signal("timeout"); + E->get()->emit_signal(SNAME("timeout")); timers.erase(E); } if (E == L) { @@ -487,10 +499,10 @@ bool SceneTree::process(float p_time) { _call_idle_callbacks(); #ifdef TOOLS_ENABLED - +#ifndef _3D_DISABLED if (Engine::get_singleton()->is_editor_hint()) { //simple hack to reload fallback environment if it changed from editor - String env_path = ProjectSettings::get_singleton()->get("rendering/environment/defaults/default_environment"); + String env_path = ProjectSettings::get_singleton()->get(SNAME("rendering/environment/defaults/default_environment")); env_path = env_path.strip_edges(); //user may have added a space or two String cpath; Ref<Environment> fallback = get_root()->get_world_3d()->get_fallback_environment(); @@ -510,8 +522,8 @@ bool SceneTree::process(float p_time) { get_root()->get_world_3d()->set_fallback_environment(fallback); } } - -#endif +#endif // _3D_DISABLED +#endif // TOOLS_ENABLED return _quit; } @@ -532,7 +544,7 @@ void SceneTree::process_tweens(float p_delta, bool p_physics) { } if (!E->get()->step(p_delta)) { - E->get()->set_valid(false); + E->get()->clear(); tweens.erase(E); } if (E == L) { @@ -559,8 +571,8 @@ void SceneTree::finalize() { } // cleanup timers - for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E; E = E->next()) { - E->get()->release_connections(); + for (Ref<SceneTreeTimer> &timer : timers) { + timer->release_connections(); } timers.clear(); } @@ -846,16 +858,7 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio } } -/* -void SceneMainLoop::_update_listener_2d() { - if (listener_2d.is_valid()) { - SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() ); - } -} - -*/ - -void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport) { +void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_call_type, const Ref<InputEvent> &p_input, Viewport *p_viewport) { Map<StringName, Group>::Element *E = group_map.find(p_group); if (!E) { return; @@ -874,9 +877,6 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p int node_count = nodes_copy.size(); Node **nodes = nodes_copy.ptrw(); - Variant arg = p_input; - const Variant *v[1] = { &arg }; - call_lock++; for (int i = node_count - 1; i >= 0; i--) { @@ -893,14 +893,16 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p continue; } - Callable::CallError err; - // Call both script and native method. - if (n->get_script_instance()) { - n->get_script_instance()->call(p_method, (const Variant **)v, 1, err); - } - MethodBind *method = ClassDB::get_method(n->get_class_name(), p_method); - if (method) { - method->call(n, (const Variant **)v, 1, err); + switch (p_call_type) { + case CALL_INPUT_TYPE_INPUT: + n->_call_input(p_input); + break; + case CALL_INPUT_TYPE_UNHANDLED_INPUT: + n->_call_unhandled_input(p_input); + break; + case CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT: + n->_call_unhandled_key_input(p_input); + break; } } @@ -927,8 +929,8 @@ Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Cal v[i] = *p_args[i + 3]; } - static_assert(VARIANT_ARG_MAX == 5, "This code needs to be updated if VARIANT_ARG_MAX != 5"); - call_group_flags(flags, group, method, v[0], v[1], v[2], v[3], v[4]); + static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); + call_group_flags(flags, group, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); return Variant(); } @@ -947,8 +949,8 @@ Variant SceneTree::_call_group(const Variant **p_args, int p_argcount, Callable: v[i] = *p_args[i + 2]; } - static_assert(VARIANT_ARG_MAX == 5, "This code needs to be updated if VARIANT_ARG_MAX != 5"); - call_group_flags(0, group, method, v[0], v[1], v[2], v[3], v[4]); + static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); + call_group_flags(0, group, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); return Variant(); } @@ -1097,7 +1099,7 @@ Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) { ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE); } - call_deferred("_change_scene", new_scene); + call_deferred(SNAME("_change_scene"), new_scene); return OK; } @@ -1112,7 +1114,7 @@ void SceneTree::add_current_scene(Node *p_current) { root->add_child(p_current); } -Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_always) { +Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always) { Ref<SceneTreeTimer> stt; stt.instantiate(); stt->set_process_always(p_process_always); @@ -1134,34 +1136,14 @@ Array SceneTree::get_processed_tweens() { ret.resize(tweens.size()); int i = 0; - for (List<Ref<Tween>>::Element *E = tweens.front(); E; E = E->next()) { - ret[i] = E->get(); + for (const Ref<Tween> &tween : tweens) { + ret[i] = tween; i++; } return ret; } -void SceneTree::_network_peer_connected(int p_id) { - emit_signal("network_peer_connected", p_id); -} - -void SceneTree::_network_peer_disconnected(int p_id) { - emit_signal("network_peer_disconnected", p_id); -} - -void SceneTree::_connected_to_server() { - emit_signal("connected_to_server"); -} - -void SceneTree::_connection_failed() { - emit_signal("connection_failed"); -} - -void SceneTree::_server_disconnected() { - emit_signal("server_disconnected"); -} - Ref<MultiplayerAPI> SceneTree::get_multiplayer() const { return multiplayer; } @@ -1177,58 +1159,8 @@ bool SceneTree::is_multiplayer_poll_enabled() const { void SceneTree::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) { ERR_FAIL_COND(!p_multiplayer.is_valid()); - if (multiplayer.is_valid()) { - multiplayer->disconnect("network_peer_connected", callable_mp(this, &SceneTree::_network_peer_connected)); - multiplayer->disconnect("network_peer_disconnected", callable_mp(this, &SceneTree::_network_peer_disconnected)); - multiplayer->disconnect("connected_to_server", callable_mp(this, &SceneTree::_connected_to_server)); - multiplayer->disconnect("connection_failed", callable_mp(this, &SceneTree::_connection_failed)); - multiplayer->disconnect("server_disconnected", callable_mp(this, &SceneTree::_server_disconnected)); - } - multiplayer = p_multiplayer; multiplayer->set_root_node(root); - - multiplayer->connect("network_peer_connected", callable_mp(this, &SceneTree::_network_peer_connected)); - multiplayer->connect("network_peer_disconnected", callable_mp(this, &SceneTree::_network_peer_disconnected)); - multiplayer->connect("connected_to_server", callable_mp(this, &SceneTree::_connected_to_server)); - multiplayer->connect("connection_failed", callable_mp(this, &SceneTree::_connection_failed)); - multiplayer->connect("server_disconnected", callable_mp(this, &SceneTree::_server_disconnected)); -} - -void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer) { - multiplayer->set_network_peer(p_network_peer); -} - -Ref<NetworkedMultiplayerPeer> SceneTree::get_network_peer() const { - return multiplayer->get_network_peer(); -} - -bool SceneTree::is_network_server() const { - return multiplayer->is_network_server(); -} - -bool SceneTree::has_network_peer() const { - return multiplayer->has_network_peer(); -} - -int SceneTree::get_network_unique_id() const { - return multiplayer->get_network_unique_id(); -} - -Vector<int> SceneTree::get_network_connected_peers() const { - return multiplayer->get_network_connected_peers(); -} - -int SceneTree::get_rpc_sender_id() const { - return multiplayer->get_rpc_sender_id(); -} - -void SceneTree::set_refuse_new_network_connections(bool p_refuse) { - multiplayer->set_refuse_new_network_connections(p_refuse); -} - -bool SceneTree::is_refusing_new_network_connections() const { - return multiplayer->is_refusing_new_network_connections(); } void SceneTree::_bind_methods() { @@ -1297,24 +1229,12 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_multiplayer"), &SceneTree::get_multiplayer); ClassDB::bind_method(D_METHOD("set_multiplayer_poll_enabled", "enabled"), &SceneTree::set_multiplayer_poll_enabled); ClassDB::bind_method(D_METHOD("is_multiplayer_poll_enabled"), &SceneTree::is_multiplayer_poll_enabled); - ClassDB::bind_method(D_METHOD("set_network_peer", "peer"), &SceneTree::set_network_peer); - ClassDB::bind_method(D_METHOD("get_network_peer"), &SceneTree::get_network_peer); - ClassDB::bind_method(D_METHOD("is_network_server"), &SceneTree::is_network_server); - ClassDB::bind_method(D_METHOD("has_network_peer"), &SceneTree::has_network_peer); - ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &SceneTree::get_network_connected_peers); - ClassDB::bind_method(D_METHOD("get_network_unique_id"), &SceneTree::get_network_unique_id); - ClassDB::bind_method(D_METHOD("get_rpc_sender_id"), &SceneTree::get_rpc_sender_id); - ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &SceneTree::set_refuse_new_network_connections); - ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &SceneTree::is_refusing_new_network_connections); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_collisions_hint"), "set_debug_collisions_hint", "is_debugging_collisions_hint"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_navigation_hint"), "set_debug_navigation_hint", "is_debugging_navigation_hint"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); - ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_edited_scene_root", "get_edited_scene_root"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_current_scene", "get_current_scene"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", PROPERTY_USAGE_NONE), "set_network_peer", "get_network_peer"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "", "get_root"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "set_multiplayer", "get_multiplayer"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multiplayer_poll"), "set_multiplayer_poll_enabled", "is_multiplayer_poll_enabled"); @@ -1330,11 +1250,6 @@ void SceneTree::_bind_methods() { ADD_SIGNAL(MethodInfo("physics_frame")); ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen"))); - ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); - ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id"))); - ADD_SIGNAL(MethodInfo("connected_to_server")); - ADD_SIGNAL(MethodInfo("connection_failed")); - ADD_SIGNAL(MethodInfo("server_disconnected")); BIND_ENUM_CONSTANT(GROUP_CALL_DEFAULT); BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE); @@ -1408,20 +1323,21 @@ SceneTree::SceneTree() { root = memnew(Window); root->set_name("root"); +#ifndef _3D_DISABLED if (!root->get_world_3d().is_valid()) { root->set_world_3d(Ref<World3D>(memnew(World3D))); } + root->set_as_audio_listener_3d(true); +#endif // _3D_DISABLED // Initialize network state. set_multiplayer(Ref<MultiplayerAPI>(memnew(MultiplayerAPI))); - //root->set_world_2d( Ref<World2D>( memnew( World2D ))); - root->set_as_audio_listener(true); root->set_as_audio_listener_2d(true); current_scene = nullptr; const int msaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/msaa", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)"))); root->set_msaa(Viewport::MSAA(msaa_mode)); const int ssaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/screen_space_aa", 0); @@ -1472,16 +1388,17 @@ SceneTree::SceneTree() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/sdf/oversize", PropertyInfo(Variant::INT, "rendering/2d/sdf/oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%")); ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/sdf/scale", PropertyInfo(Variant::INT, "rendering/2d/sdf/scale", PROPERTY_HINT_ENUM, "100%,50%,25%")); +#ifndef _3D_DISABLED { // Load default fallback environment. // Get possible extensions. List<String> exts; ResourceLoader::get_recognized_extensions_for_type("Environment", &exts); String ext_hint; - for (List<String>::Element *E = exts.front(); E; E = E->next()) { + for (const String &E : exts) { if (ext_hint != String()) { ext_hint += ","; } - ext_hint += "*." + E->get(); + ext_hint += "*." + E; } // Get path. String env_path = GLOBAL_DEF("rendering/environment/defaults/default_environment", ""); @@ -1503,6 +1420,7 @@ SceneTree::SceneTree() { } } } +#endif // _3D_DISABLED root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true)); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 0e9ffb0f5f..19331c1906 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -31,7 +31,7 @@ #ifndef SCENE_TREE_H #define SCENE_TREE_H -#include "core/io/multiplayer_api.h" +#include "core/multiplayer/multiplayer_api.h" #include "core/os/main_loop.h" #include "core/os/thread_safe.h" #include "core/templates/self_list.h" @@ -52,19 +52,23 @@ class Tween; class SceneTreeTimer : public RefCounted { GDCLASS(SceneTreeTimer, RefCounted); - float time_left = 0.0; + double time_left = 0.0; bool process_always = true; + bool ignore_time_scale = false; protected: static void _bind_methods(); public: - void set_time_left(float p_time); - float get_time_left() const; + void set_time_left(double p_time); + double get_time_left() const; void set_process_always(bool p_process_always); bool is_process_always(); + void set_ignore_time_scale(bool p_ignore); + bool is_ignore_time_scale(); + void release_connections(); SceneTreeTimer(); @@ -87,8 +91,8 @@ private: Window *root = nullptr; uint64_t tree_version = 1; - float physics_process_time = 1.0; - float process_time = 1.0; + double physics_process_time = 1.0; + double process_time = 1.0; bool accept_quit = true; bool quit_on_go_back = true; @@ -159,13 +163,6 @@ private: Ref<MultiplayerAPI> multiplayer; bool multiplayer_poll = true; - void _network_peer_connected(int p_id); - void _network_peer_disconnected(int p_id); - - void _connected_to_server(); - void _connection_failed(); - void _server_disconnected(); - static SceneTree *singleton; friend class Node; @@ -207,8 +204,14 @@ private: void _main_window_close(); void _main_window_go_back(); + enum CallInputType { + CALL_INPUT_TYPE_INPUT, + CALL_INPUT_TYPE_UNHANDLED_INPUT, + CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT, + }; + //used by viewport - void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport); + void _call_input_pause(const StringName &p_group, CallInputType p_call_type, const Ref<InputEvent> &p_input, Viewport *p_viewport); protected: void _notification(int p_notification); @@ -240,8 +243,8 @@ public: virtual void initialize() override; - virtual bool physics_process(float p_time) override; - virtual bool process(float p_time) override; + virtual bool physics_process(double p_time) override; + virtual bool process(double p_time) override; virtual void finalize() override; @@ -250,8 +253,8 @@ public: void quit(int p_exit_code = EXIT_SUCCESS); - _FORCE_INLINE_ float get_physics_process_time() const { return physics_process_time; } - _FORCE_INLINE_ float get_process_time() const { return process_time; } + _FORCE_INLINE_ double get_physics_process_time() const { return physics_process_time; } + _FORCE_INLINE_ double get_process_time() const { return process_time; } #ifdef TOOLS_ENABLED bool is_node_being_edited(const Node *p_node) const; @@ -320,7 +323,7 @@ public: Error change_scene_to(const Ref<PackedScene> &p_scene); Error reload_current_scene(); - Ref<SceneTreeTimer> create_timer(float p_delay_sec, bool p_process_always = true); + Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true); Ref<Tween> create_tween(); Array get_processed_tweens(); @@ -337,16 +340,6 @@ public: void set_multiplayer_poll_enabled(bool p_enabled); bool is_multiplayer_poll_enabled() const; void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer); - void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer); - Ref<NetworkedMultiplayerPeer> get_network_peer() const; - bool is_network_server() const; - bool has_network_peer() const; - int get_network_unique_id() const; - Vector<int> get_network_connected_peers() const; - int get_rpc_sender_id() const; - - void set_refuse_new_network_connections(bool p_refuse); - bool is_refusing_new_network_connections() const; static void add_idle_callback(IdleCallback p_callback); diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp index 3d65c12cb7..9477e300d1 100644 --- a/scene/main/shader_globals_override.cpp +++ b/scene/main/shader_globals_override.cpp @@ -30,8 +30,7 @@ #include "shader_globals_override.h" -#include "core/core_string_names.h" -#include "scene/main/window.h" +#include "scene/3d/node_3d.h" #include "scene/scene_string_names.h" StringName *ShaderGlobalsOverride::_remap(const StringName &p_name) const { @@ -63,7 +62,12 @@ bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_valu if (o) { o->override = p_value; if (active) { - RS::get_singleton()->global_variable_set_override(*r, p_value); + if (o->override.get_type() == Variant::OBJECT) { + RID tex_rid = p_value; + RS::get_singleton()->global_variable_set_override(*r, tex_rid); + } else { + RS::get_singleton()->global_variable_set_override(*r, p_value); + } } o->in_use = p_value.get_type() != Variant::NIL; return true; @@ -228,7 +232,12 @@ void ShaderGlobalsOverride::_activate() { while ((K = overrides.next(K))) { Override *o = overrides.getptr(*K); if (o->in_use && o->override.get_type() != Variant::NIL) { - RS::get_singleton()->global_variable_set_override(*K, o->override); + if (o->override.get_type() == Variant::OBJECT) { + RID tex_rid = o->override; + RS::get_singleton()->global_variable_set_override(*K, tex_rid); + } else { + RS::get_singleton()->global_variable_set_override(*K, o->override); + } } } diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h index 2d9c3c76bd..ab4b9de727 100644 --- a/scene/main/shader_globals_override.h +++ b/scene/main/shader_globals_override.h @@ -31,7 +31,7 @@ #ifndef SHADER_GLOBALS_OVERRIDE_H #define SHADER_GLOBALS_OVERRIDE_H -#include "scene/3d/node_3d.h" +#include "scene/main/node.h" class ShaderGlobalsOverride : public Node { GDCLASS(ShaderGlobalsOverride, Node); diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index f52237251c..9e462eb1c8 100644 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -30,8 +30,6 @@ #include "timer.h" -#include "core/config/engine.h" - void Timer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { @@ -58,7 +56,7 @@ void Timer::_notification(int p_what) { stop(); } - emit_signal("timeout"); + emit_signal(SNAME("timeout")); } } break; @@ -74,19 +72,19 @@ void Timer::_notification(int p_what) { } else { stop(); } - emit_signal("timeout"); + emit_signal(SNAME("timeout")); } } break; } } -void Timer::set_wait_time(float p_time) { +void Timer::set_wait_time(double p_time) { ERR_FAIL_COND_MSG(p_time <= 0, "Time should be greater than zero."); wait_time = p_time; } -float Timer::get_wait_time() const { +double Timer::get_wait_time() const { return wait_time; } @@ -106,7 +104,7 @@ bool Timer::has_autostart() const { return autostart; } -void Timer::start(float p_time) { +void Timer::start(double p_time) { ERR_FAIL_COND_MSG(!is_inside_tree(), "Timer was not added to the SceneTree. Either add it or set autostart to true."); if (p_time > 0) { @@ -139,7 +137,7 @@ bool Timer::is_stopped() const { return get_time_left() <= 0; } -float Timer::get_time_left() const { +double Timer::get_time_left() const { return time_left > 0 ? time_left : 0; } diff --git a/scene/main/timer.h b/scene/main/timer.h index 3d9e21d7fc..2b9faddcb9 100644 --- a/scene/main/timer.h +++ b/scene/main/timer.h @@ -36,7 +36,7 @@ class Timer : public Node { GDCLASS(Timer, Node); - float wait_time = 1.0; + double wait_time = 1.0; bool one_shot = false; bool autostart = false; bool processing = false; @@ -54,8 +54,8 @@ public: TIMER_PROCESS_IDLE, }; - void set_wait_time(float p_time); - float get_wait_time() const; + void set_wait_time(double p_time); + double get_wait_time() const; void set_one_shot(bool p_one_shot); bool is_one_shot() const; @@ -63,7 +63,7 @@ public: void set_autostart(bool p_start); bool has_autostart() const; - void start(float p_time = -1); + void start(double p_time = -1); void stop(); void set_paused(bool p_paused); @@ -71,7 +71,7 @@ public: bool is_stopped() const; - float get_time_left() const; + double get_time_left() const; void set_timer_process_callback(TimerProcessCallback p_callback); TimerProcessCallback get_timer_process_callback() const; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 9a2e0c5230..fb86d37280 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -30,32 +30,31 @@ #include "viewport.h" -#include "core/config/project_settings.h" #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" -#include "core/input/input.h" -#include "core/os/os.h" +#include "core/object/message_queue.h" #include "core/string/translation.h" - +#include "core/templates/pair.h" +#include "scene/2d/camera_2d.h" #include "scene/2d/collision_object_2d.h" +#include "scene/2d/listener_2d.h" +#ifndef _3D_DISABLED #include "scene/3d/camera_3d.h" #include "scene/3d/collision_object_3d.h" #include "scene/3d/listener_3d.h" -#include "scene/3d/node_3d.h" #include "scene/3d/world_environment.h" +#endif // _3D_DISABLED #include "scene/gui/control.h" #include "scene/gui/label.h" -#include "scene/gui/menu_button.h" -#include "scene/gui/panel.h" -#include "scene/gui/panel_container.h" +#include "scene/gui/popup.h" #include "scene/gui/popup_menu.h" #include "scene/main/canvas_layer.h" -#include "scene/main/timer.h" #include "scene/main/window.h" #include "scene/resources/mesh.h" +#include "scene/resources/text_line.h" +#include "scene/resources/world_2d.h" #include "scene/scene_string_names.h" -#include "servers/display_server.h" -#include "servers/physics_server_2d.h" +#include "servers/audio_server.h" void ViewportTexture::setup_local_to_scene() { if (vp) { @@ -82,7 +81,7 @@ void ViewportTexture::setup_local_to_scene() { RS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid); RS::get_singleton()->free(proxy_ph); } else { - ERR_FAIL_COND(proxy.is_valid()); //should be invalid + ERR_FAIL_COND(proxy.is_valid()); // Should be invalid. proxy = RS::get_singleton()->texture_proxy_create(vp->texture_rid); } } @@ -119,7 +118,6 @@ Size2 ViewportTexture::get_size() const { } RID ViewportTexture::get_rid() const { - //ERR_FAIL_COND_V_MSG(!vp, RID(), "Viewport Texture must be set to use it."); if (proxy.is_null()) { proxy_ph = RS::get_singleton()->texture_2d_placeholder_create(); proxy = RS::get_singleton()->texture_proxy_create(proxy_ph); @@ -183,24 +181,6 @@ public: ///////////////////////////////////// -void Viewport::_collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) { - Transform3D object_transform = p_object->get_global_transform(); - Transform3D camera_transform = p_camera->get_global_transform(); - ObjectID id = p_object->get_instance_id(); - - //avoid sending the fake event unnecessarily if nothing really changed in the context - if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) { - Ref<InputEventMouseMotion> mm = p_input_event; - if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { - return; //discarded - } - } - p_object->_input_event(camera, p_input_event, p_pos, p_normal, p_shape); - physics_last_object_transform = object_transform; - physics_last_camera_transform = camera_transform; - physics_last_id = id; -} - void Viewport::_sub_window_update_order() { for (int i = 0; i < gui.sub_windows.size(); i++) { RS::get_singleton()->canvas_item_set_draw_index(gui.sub_windows[i].canvas_item, i); @@ -248,33 +228,32 @@ void Viewport::_sub_window_update(Window *p_window) { Rect2i r = Rect2i(p_window->get_position(), sw.window->get_size()); if (!p_window->get_flag(Window::FLAG_BORDERLESS)) { - Ref<StyleBox> panel = p_window->get_theme_stylebox("panel_window"); + Ref<StyleBox> panel = p_window->get_theme_stylebox(SNAME("embedded_border")); panel->draw(sw.canvas_item, r); // Draw the title bar text. - Ref<Font> title_font = p_window->get_theme_font("title_font"); - int font_size = p_window->get_theme_font_size("title_font_size"); - Color title_color = p_window->get_theme_color("title_color"); - int title_height = p_window->get_theme_constant("title_height"); - int close_h_ofs = p_window->get_theme_constant("close_h_ofs"); - int close_v_ofs = p_window->get_theme_constant("close_v_ofs"); - - TextLine title_text = TextLine(p_window->get_title(), title_font, font_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); + Ref<Font> title_font = p_window->get_theme_font(SNAME("title_font")); + int font_size = p_window->get_theme_font_size(SNAME("title_font_size")); + Color title_color = p_window->get_theme_color(SNAME("title_color")); + int title_height = p_window->get_theme_constant(SNAME("title_height")); + int close_h_ofs = p_window->get_theme_constant(SNAME("close_h_ofs")); + int close_v_ofs = p_window->get_theme_constant(SNAME("close_v_ofs")); + + TextLine title_text = TextLine(p_window->atr(p_window->get_title()), title_font, font_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); title_text.set_width(r.size.width - panel->get_minimum_size().x - close_h_ofs); title_text.set_direction(p_window->is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); int x = (r.size.width - title_text.get_size().x) / 2; int y = (-title_height - title_text.get_size().y) / 2; - Color font_outline_color = p_window->get_theme_color("title_outline_modulate"); - int outline_size = p_window->get_theme_constant("title_outline_size"); + Color font_outline_color = p_window->get_theme_color(SNAME("title_outline_modulate")); + int outline_size = p_window->get_theme_constant(SNAME("title_outline_size")); if (outline_size > 0 && font_outline_color.a > 0) { title_text.draw_outline(sw.canvas_item, r.position + Point2(x, y), outline_size, font_outline_color); } title_text.draw(sw.canvas_item, r.position + Point2(x, y), title_color); - bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside; - - Ref<Texture2D> close_icon = p_window->get_theme_icon(hl ? "close_highlight" : "close"); + bool pressed = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside; + Ref<Texture2D> close_icon = p_window->get_theme_icon(pressed ? "close_pressed" : "close"); close_icon->draw(sw.canvas_item, r.position + Vector2(r.size.width - close_h_ofs, -close_v_ofs)); } @@ -283,7 +262,7 @@ void Viewport::_sub_window_update(Window *p_window) { void Viewport::_sub_window_grab_focus(Window *p_window) { if (p_window == nullptr) { - //release current focus + // Release current focus. if (gui.subwindow_focused) { gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); gui.subwindow_focused = nullptr; @@ -309,18 +288,18 @@ void Viewport::_sub_window_grab_focus(Window *p_window) { ERR_FAIL_COND(index == -1); if (p_window->get_flag(Window::FLAG_NO_FOCUS)) { - //can only move to foreground, but no focus granted + // Can only move to foreground, but no focus granted. SubWindow sw = gui.sub_windows[index]; gui.sub_windows.remove(index); gui.sub_windows.push_back(sw); index = gui.sub_windows.size() - 1; _sub_window_update_order(); - return; //i guess not... + return; } if (gui.subwindow_focused) { if (gui.subwindow_focused == p_window) { - return; //nothing to do + return; // Nothing to do. } gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; @@ -337,7 +316,7 @@ void Viewport::_sub_window_grab_focus(Window *p_window) { gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); - { //move to foreground + { // Move to foreground. SubWindow sw = gui.sub_windows[index]; gui.sub_windows.remove(index); gui.sub_windows.push_back(sw); @@ -388,27 +367,6 @@ void Viewport::_sub_window_remove(Window *p_window) { RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID()); } -void Viewport::_own_world_3d_changed() { - ERR_FAIL_COND(world_3d.is_null()); - ERR_FAIL_COND(own_world_3d.is_null()); - - if (is_inside_tree()) { - _propagate_exit_world(this); - } - - own_world_3d = world_3d->duplicate(); - - if (is_inside_tree()) { - _propagate_enter_world(this); - } - - if (is_inside_tree()) { - RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario()); - } - - _update_listener(); -} - void Viewport::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -422,19 +380,19 @@ void Viewport::_notification(int p_what) { } current_canvas = find_world_2d()->get_canvas(); - RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario()); RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas); - - _update_listener(); _update_listener_2d(); +#ifndef _3D_DISABLED + RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario()); + _update_listener_3d(); +#endif // _3D_DISABLED add_to_group("_viewports"); if (get_tree()->is_debugging_collisions_hint()) { - //2D PhysicsServer2D::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(), get_tree()->get_collision_debug_contact_count()); contact_2d_debug = RenderingServer::get_singleton()->canvas_item_create(); RenderingServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, find_world_2d()->get_canvas()); - //3D +#ifndef _3D_DISABLED PhysicsServer3D::get_singleton()->space_set_debug_contacts(find_world_3d()->get_space(), get_tree()->get_collision_debug_contact_count()); contact_3d_debug_multimesh = RenderingServer::get_singleton()->multimesh_create(); RenderingServer::get_singleton()->multimesh_allocate_data(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, true); @@ -444,14 +402,15 @@ void Viewport::_notification(int p_what) { RenderingServer::get_singleton()->instance_set_base(contact_3d_debug_instance, contact_3d_debug_multimesh); RenderingServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world_3d()->get_scenario()); //RenderingServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, RS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true); +#endif // _3D_DISABLED } } break; case NOTIFICATION_READY: { #ifndef _3D_DISABLED - if (listeners.size() && !listener) { + if (listener_3d_set.size() && !listener_3d) { Listener3D *first = nullptr; - for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) { + for (Set<Listener3D *>::Element *E = listener_3d_set.front(); E; E = E->next()) { if (first == nullptr || first->is_greater_than(E->get())) { first = E->get(); } @@ -462,10 +421,10 @@ void Viewport::_notification(int p_what) { } } - if (cameras.size() && !camera) { - //there are cameras but no current camera, pick first in tree and make it current + if (camera_3d_set.size() && !camera_3d) { + // There are cameras but no current camera, pick first in tree and make it current. Camera3D *first = nullptr; - for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) { + for (Set<Camera3D *>::Element *E = camera_3d_set.front(); E; E = E->next()) { if (first == nullptr || first->is_greater_than(E->get())) { first = E->get(); } @@ -475,12 +434,7 @@ void Viewport::_notification(int p_what) { first->make_current(); } } -#endif - - // Enable processing for tooltips, collision debugging, physics object picking, etc. - set_process_internal(true); - set_physics_process_internal(true); - +#endif // _3D_DISABLED } break; case NOTIFICATION_EXIT_TREE: { _gui_cancel_tooltip(); @@ -500,19 +454,10 @@ void Viewport::_notification(int p_what) { } remove_from_group("_viewports"); + set_physics_process_internal(false); RS::get_singleton()->viewport_set_active(viewport, false); RenderingServer::get_singleton()->viewport_set_parent_viewport(viewport, RID()); - - } break; - case NOTIFICATION_INTERNAL_PROCESS: { - if (gui.tooltip_timer >= 0) { - gui.tooltip_timer -= get_process_delta_time(); - if (gui.tooltip_timer < 0) { - _gui_show_tooltip(); - } - } - } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) { @@ -527,7 +472,7 @@ void Viewport::_notification(int p_what) { RenderingServer::get_singleton()->canvas_item_add_rect(contact_2d_debug, Rect2(points[i] - Vector2(2, 2), Vector2(5, 5)), ccol); } } - +#ifndef _3D_DISABLED if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) { Vector<Vector3> points = PhysicsServer3D::get_singleton()->space_get_contacts(find_world_3d()->get_space()); int point_count = PhysicsServer3D::get_singleton()->space_get_contact_count(find_world_3d()->get_space()); @@ -540,6 +485,7 @@ void Viewport::_notification(int p_what) { RS::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh, i, point_transform); } } +#endif // _3D_DISABLED } break; case NOTIFICATION_WM_MOUSE_EXIT: { _drop_physics_mouseover(); @@ -572,20 +518,14 @@ void Viewport::_process_picking() { _drop_physics_mouseover(true); -#ifndef _3D_DISABLED - Vector2 last_pos(1e20, 1e20); - CollisionObject3D *last_object = nullptr; - ObjectID last_id; -#endif - PhysicsDirectSpaceState3D::RayResult result; PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space()); if (physics_has_last_mousepos) { - // if no mouse event exists, create a motion one. This is necessary because objects or camera may have moved. - // while this extra event is sent, it is checked if both camera and last object and last ID did not move. If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame + // If no mouse event exists, create a motion one. This is necessary because objects or camera may have moved. + // While this extra event is sent, it is checked if both camera and last object and last ID did not move. + // If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame. bool has_mouse_event = false; - for (List<Ref<InputEvent>>::Element *E = physics_picking_events.front(); E; E = E->next()) { - Ref<InputEventMouse> m = E->get(); + for (const Ref<InputEvent> &m : physics_picking_events) { if (m.is_valid()) { has_mouse_event = true; break; @@ -657,7 +597,7 @@ void Viewport::_process_picking() { Ref<InputEventKey> k = ev; if (k.is_valid()) { - //only for mask + // Only for mask. physics_last_mouse_state.alt = k->is_alt_pressed(); physics_last_mouse_state.shift = k->is_shift_pressed(); physics_last_mouse_state.control = k->is_ctrl_pressed(); @@ -678,7 +618,7 @@ void Viewport::_process_picking() { } if (ss2d) { - //send to 2D + // Send to 2D. uint64_t frame = get_tree()->get_frame(); @@ -687,11 +627,11 @@ void Viewport::_process_picking() { Transform2D canvas_transform; ObjectID canvas_layer_id; if (E->get()) { - // A descendant CanvasLayer + // A descendant CanvasLayer. canvas_transform = E->get()->get_transform(); canvas_layer_id = E->get()->get_instance_id(); } else { - // This Viewport's builtin canvas + // This Viewport's builtin canvas. canvas_transform = get_canvas_transform(); canvas_layer_id = ObjectID(); } @@ -706,21 +646,27 @@ void Viewport::_process_picking() { bool send_event = true; if (is_mouse) { Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id); - if (!F) { physics_2d_mouseover.insert(res[i].collider_id, frame); co->_mouse_enter(); } else { F->get() = frame; - // It was already hovered, so don't send the event if it's faked + // It was already hovered, so don't send the event if it's faked. if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { send_event = false; } } + Map<Pair<ObjectID, int>, uint64_t, PairSort<ObjectID, int>>::Element *SF = physics_2d_shape_mouseover.find(Pair(res[i].collider_id, res[i].shape)); + if (!SF) { + physics_2d_shape_mouseover.insert(Pair(res[i].collider_id, res[i].shape), frame); + co->_mouse_shape_enter(res[i].shape); + } else { + SF->get() = frame; + } } if (send_event) { - co->_input_event(this, ev, res[i].shape); + co->_input_event_call(this, ev, res[i].shape); } } } @@ -728,35 +674,21 @@ void Viewport::_process_picking() { } if (is_mouse) { - List<Map<ObjectID, uint64_t>::Element *> to_erase; - - for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) { - if (E->get() != frame) { - Object *o = ObjectDB::get_instance(E->key()); - if (o) { - CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); - if (co) { - co->_mouse_exit(); - } - } - to_erase.push_back(E); - } - } - - while (to_erase.size()) { - physics_2d_mouseover.erase(to_erase.front()->get()); - to_erase.pop_front(); - } + _cleanup_mouseover_colliders(false, false, frame); } } #ifndef _3D_DISABLED + Vector2 last_pos(1e20, 1e20); + CollisionObject3D *last_object = nullptr; + ObjectID last_id; + PhysicsDirectSpaceState3D::RayResult result; bool captured = false; if (physics_object_capture.is_valid()) { CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture)); - if (co && camera) { - _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0); + if (co && camera_3d) { + _collision_object_3d_input_event(co, camera_3d, ev, Vector3(), Vector3(), 0); captured = true; if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) { physics_object_capture = ObjectID(); @@ -768,21 +700,21 @@ void Viewport::_process_picking() { } if (captured) { - //none + // None. } else if (pos == last_pos) { if (last_id.is_valid()) { if (ObjectDB::get_instance(last_id) && last_object) { - //good, exists - _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape); + // Good, exists. + _collision_object_3d_input_event(last_object, camera_3d, ev, result.position, result.normal, result.shape); if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { physics_object_capture = last_id; } } } } else { - if (camera) { - Vector3 from = camera->project_ray_origin(pos); - Vector3 dir = camera->project_ray_normal(pos); + if (camera_3d) { + Vector3 from = camera_3d->project_ray_origin(pos); + Vector3 dir = camera_3d->project_ray_normal(pos); PhysicsDirectSpaceState3D *space = PhysicsServer3D::get_singleton()->space_get_direct_state(find_world_3d()->get_space()); if (space) { @@ -791,7 +723,7 @@ void Viewport::_process_picking() { if (col) { CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider); if (co && co->can_process()) { - _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape); + _collision_object_3d_input_event(co, camera_3d, ev, result.position, result.normal, result.shape); last_object = co; last_id = result.collider_id; new_collider = last_id; @@ -823,7 +755,7 @@ void Viewport::_process_picking() { last_pos = pos; } } -#endif +#endif // _3D_DISABLED } } @@ -859,7 +791,7 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, update_canvas_items(); - emit_signal("size_changed"); + emit_signal(SNAME("size_changed")); } Size2i Viewport::_get_size() const { @@ -890,29 +822,10 @@ Rect2 Viewport::get_visible_rect() const { return r; } -void Viewport::_update_listener() { -} - void Viewport::_update_listener_2d() { - /* - if (is_inside_tree() && audio_listener && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree()))) - SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, find_world_2d()->get_sound_space()); - else - SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, RID()); -*/ -} - -void Viewport::set_as_audio_listener(bool p_enable) { - if (p_enable == audio_listener) { - return; + if (AudioServer::get_singleton()) { + AudioServer::get_singleton()->notify_listener_changed(); } - - audio_listener = p_enable; - _update_listener(); -} - -bool Viewport::is_audio_listener() const { - return audio_listener; } void Viewport::set_as_audio_listener_2d(bool p_enable) { @@ -921,7 +834,6 @@ void Viewport::set_as_audio_listener_2d(bool p_enable) { } audio_listener_2d = p_enable; - _update_listener_2d(); } @@ -929,13 +841,8 @@ bool Viewport::is_audio_listener_2d() const { return audio_listener_2d; } -void Viewport::set_disable_3d(bool p_disable) { - disable_3d = p_disable; - RenderingServer::get_singleton()->viewport_set_disable_3d(viewport, disable_3d); -} - -bool Viewport::is_3d_disabled() const { - return disable_3d; +Listener2D *Viewport::get_listener_2d() const { + return listener_2d; } void Viewport::enable_canvas_transform_override(bool p_enable) { @@ -998,127 +905,25 @@ Transform2D Viewport::get_global_canvas_transform() const { return global_canvas_transform; } -void Viewport::_listener_transform_changed_notify() { +void Viewport::_camera_2d_set(Camera2D *p_camera_2d) { + camera_2d = p_camera_2d; } -void Viewport::_listener_set(Listener3D *p_listener) { -#ifndef _3D_DISABLED - - if (listener == p_listener) { +void Viewport::_listener_2d_set(Listener2D *p_listener) { + if (listener_2d == p_listener) { return; + } else if (listener_2d) { + listener_2d->clear_current(); } - - listener = p_listener; - - _update_listener(); - _listener_transform_changed_notify(); -#endif + listener_2d = p_listener; } -bool Viewport::_listener_add(Listener3D *p_listener) { - listeners.insert(p_listener); - return listeners.size() == 1; -} - -void Viewport::_listener_remove(Listener3D *p_listener) { - listeners.erase(p_listener); - if (listener == p_listener) { - listener = nullptr; +void Viewport::_listener_2d_remove(Listener2D *p_listener) { + if (listener_2d == p_listener) { + listener_2d = nullptr; } } -#ifndef _3D_DISABLED -void Viewport::_listener_make_next_current(Listener3D *p_exclude) { - if (listeners.size() > 0) { - for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) { - if (p_exclude == E->get()) { - continue; - } - if (!E->get()->is_inside_tree()) { - continue; - } - if (listener != nullptr) { - return; - } - - E->get()->make_current(); - } - } else { - // Attempt to reset listener to the camera position - if (camera != nullptr) { - _update_listener(); - _camera_transform_changed_notify(); - } - } -} -#endif - -void Viewport::_camera_transform_changed_notify() { -#ifndef _3D_DISABLED -#endif -} - -void Viewport::_camera_set(Camera3D *p_camera) { -#ifndef _3D_DISABLED - - if (camera == p_camera) { - return; - } - - if (camera) { - camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT); - } - - camera = p_camera; - - if (!camera_override) { - if (camera) { - RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera()); - } else { - RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID()); - } - } - - if (camera) { - camera->notification(Camera3D::NOTIFICATION_BECAME_CURRENT); - } - - _update_listener(); - _camera_transform_changed_notify(); -#endif -} - -bool Viewport::_camera_add(Camera3D *p_camera) { - cameras.insert(p_camera); - return cameras.size() == 1; -} - -void Viewport::_camera_remove(Camera3D *p_camera) { - cameras.erase(p_camera); - if (camera == p_camera) { - camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT); - camera = nullptr; - } -} - -#ifndef _3D_DISABLED -void Viewport::_camera_make_next_current(Camera3D *p_exclude) { - for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) { - if (p_exclude == E->get()) { - continue; - } - if (!E->get()->is_inside_tree()) { - continue; - } - if (camera != nullptr) { - return; - } - - E->get()->make_current(); - } -} -#endif - void Viewport::_canvas_layer_add(CanvasLayer *p_canvas_layer) { canvas_layers.insert(p_canvas_layer); } @@ -1142,7 +947,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) { } if (parent && parent->find_world_2d() == p_world_2d) { - WARN_PRINT("Unable to use parent world_3d as world_2d"); + WARN_PRINT("Unable to use parent world_2d as world_2d"); return; } @@ -1175,33 +980,6 @@ Ref<World2D> Viewport::find_world_2d() const { } } -void Viewport::_propagate_enter_world(Node *p_node) { - if (p_node != this) { - if (!p_node->is_inside_tree()) { //may not have entered scene yet - return; - } - -#ifndef _3D_DISABLED - if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) { - p_node->notification(Node3D::NOTIFICATION_ENTER_WORLD); - } else { -#endif - Viewport *v = Object::cast_to<Viewport>(p_node); - if (v) { - if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) { - return; - } - } -#ifndef _3D_DISABLED - } -#endif - } - - for (int i = 0; i < p_node->get_child_count(); i++) { - _propagate_enter_world(p_node->get_child(i)); - } -} - void Viewport::_propagate_viewport_notification(Node *p_node, int p_what) { p_node->notification(p_what); for (int i = 0; i < p_node->get_child_count(); i++) { @@ -1213,168 +991,12 @@ void Viewport::_propagate_viewport_notification(Node *p_node, int p_what) { } } -void Viewport::_propagate_exit_world(Node *p_node) { - if (p_node != this) { - if (!p_node->is_inside_tree()) { //may have exited scene already - return; - } - -#ifndef _3D_DISABLED - if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) { - p_node->notification(Node3D::NOTIFICATION_EXIT_WORLD); - } else { -#endif - Viewport *v = Object::cast_to<Viewport>(p_node); - if (v) { - if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) { - return; - } - } -#ifndef _3D_DISABLED - } -#endif - } - - for (int i = 0; i < p_node->get_child_count(); i++) { - _propagate_exit_world(p_node->get_child(i)); - } -} - -void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) { - if (world_3d == p_world_3d) { - return; - } - - if (is_inside_tree()) { - _propagate_exit_world(this); - } - - if (own_world_3d.is_valid() && world_3d.is_valid()) { - world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); - } - - world_3d = p_world_3d; - - if (own_world_3d.is_valid()) { - if (world_3d.is_valid()) { - own_world_3d = world_3d->duplicate(); - world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); - } else { - own_world_3d = Ref<World3D>(memnew(World3D)); - } - } - - if (is_inside_tree()) { - _propagate_enter_world(this); - } - - if (is_inside_tree()) { - RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario()); - } - - _update_listener(); -} - -Ref<World3D> Viewport::get_world_3d() const { - return world_3d; -} - Ref<World2D> Viewport::get_world_2d() const { return world_2d; } -Ref<World3D> Viewport::find_world_3d() const { - if (own_world_3d.is_valid()) { - return own_world_3d; - } else if (world_3d.is_valid()) { - return world_3d; - } else if (parent) { - return parent->find_world_3d(); - } else { - return Ref<World3D>(); - } -} - -Listener3D *Viewport::get_listener() const { - return listener; -} - -Camera3D *Viewport::get_camera() const { - return camera; -} - -void Viewport::enable_camera_override(bool p_enable) { -#ifndef _3D_DISABLED - if (p_enable == camera_override) { - return; - } - - if (p_enable) { - camera_override.rid = RenderingServer::get_singleton()->camera_create(); - } else { - RenderingServer::get_singleton()->free(camera_override.rid); - camera_override.rid = RID(); - } - - if (p_enable) { - RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid); - } else if (camera) { - RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera()); - } else { - RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID()); - } -#endif -} - -bool Viewport::is_camera_override_enabled() const { - return camera_override; -} - -void Viewport::set_camera_override_transform(const Transform3D &p_transform) { - if (camera_override) { - camera_override.transform = p_transform; - RenderingServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform); - } -} - -Transform3D Viewport::get_camera_override_transform() const { - if (camera_override) { - return camera_override.transform; - } - - return Transform3D(); -} - -void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) { - if (camera_override) { - if (camera_override.fov == p_fovy_degrees && camera_override.z_near == p_z_near && - camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_PERSPECTIVE) { - return; - } - - camera_override.fov = p_fovy_degrees; - camera_override.z_near = p_z_near; - camera_override.z_far = p_z_far; - camera_override.projection = CameraOverrideData::PROJECTION_PERSPECTIVE; - - RenderingServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far); - } -} - -void Viewport::set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far) { - if (camera_override) { - if (camera_override.size == p_size && camera_override.z_near == p_z_near && - camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_ORTHOGONAL) { - return; - } - - camera_override.size = p_size; - camera_override.z_near = p_z_near; - camera_override.z_far = p_z_far; - camera_override.projection = CameraOverrideData::PROJECTION_ORTHOGONAL; - - RenderingServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far); - } +Camera2D *Viewport::get_camera_2d() const { + return camera_2d; } Transform2D Viewport::get_final_transform() const { @@ -1401,16 +1023,6 @@ void Viewport::_update_canvas_items(Node *p_node) { } } -void Viewport::set_use_xr(bool p_use_xr) { - use_xr = p_use_xr; - - RS::get_singleton()->viewport_set_use_xr(viewport, use_xr); -} - -bool Viewport::is_using_xr() { - return use_xr; -} - Ref<ViewportTexture> Viewport::get_texture() const { return default_texture; } @@ -1493,7 +1105,10 @@ void Viewport::_gui_sort_roots() { void Viewport::_gui_cancel_tooltip() { gui.tooltip_control = nullptr; - gui.tooltip_timer = -1; + if (gui.tooltip_timer.is_valid()) { + gui.tooltip_timer->release_connections(); + gui.tooltip_timer = Ref<SceneTreeTimer>(); + } if (gui.tooltip_popup) { gui.tooltip_popup->queue_delete(); gui.tooltip_popup = nullptr; @@ -1508,6 +1123,12 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont while (p_control) { tooltip = p_control->get_tooltip(pos); + // Temporary solution for PopupMenus. + PopupMenu *menu = Object::cast_to<PopupMenu>(this); + if (menu) { + tooltip = menu->get_tooltip(pos); + } + if (r_tooltip_owner) { *r_tooltip_owner = p_control; } @@ -1562,6 +1183,9 @@ void Viewport::_gui_show_tooltip() { return; } + // Popup window which houses the tooltip content. + TooltipPanel *panel = memnew(TooltipPanel); + // Controls can implement `make_custom_tooltip` to provide their own tooltip. // This should be a Control node which will be added as child to a TooltipPanel. Control *base_tooltip = tooltip_owner->make_custom_tooltip(tooltip_text); @@ -1569,13 +1193,14 @@ void Viewport::_gui_show_tooltip() { // If no custom tooltip is given, use a default implementation. if (!base_tooltip) { gui.tooltip_label = memnew(TooltipLabel); + gui.tooltip_label->set_auto_translate(gui.tooltip_control->is_auto_translating()); gui.tooltip_label->set_text(tooltip_text); base_tooltip = gui.tooltip_label; + panel->connect("mouse_entered", callable_mp(this, &Viewport::_gui_cancel_tooltip)); } base_tooltip->set_anchors_and_offsets_preset(Control::PRESET_WIDE); - TooltipPanel *panel = memnew(TooltipPanel); panel->set_transient(false); panel->set_flag(Window::FLAG_NO_FOCUS, true); panel->set_wrap_controls(true); @@ -1612,11 +1237,9 @@ void Viewport::_gui_show_tooltip() { } void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_input) { - //_block(); - Ref<InputEvent> ev = p_input; - //mouse wheel events can't be stopped + // Mouse wheel events can't be stopped. Ref<InputEventMouseButton> mb = p_input; bool cant_stop_me_now = (mb.is_valid() && @@ -1634,27 +1257,7 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu Control *control = Object::cast_to<Control>(ci); if (control) { if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) { - control->emit_signal(SceneStringNames::get_singleton()->gui_input, ev); //signal should be first, so it's possible to override an event (and then accept it) - } - if (gui.key_event_accepted) { - break; - } - if (!control->is_inside_tree()) { - break; - } - - if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) { - // Call both script and native methods. - Callable::CallError error; - Variant event = ev; - const Variant *args[1] = { &event }; - if (control->get_script_instance()) { - control->get_script_instance()->call(SceneStringNames::get_singleton()->_gui_input, args, 1, error); - } - MethodBind *method = ClassDB::get_method(control->get_class_name(), SceneStringNames::get_singleton()->_gui_input); - if (method) { - method->call(control, args, 1, error); - } + control->_call_gui_input(ev); } if (!control->is_inside_tree() || control->is_set_as_top_level()) { @@ -1672,11 +1275,9 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu break; } - ev = ev->xformed_by(ci->get_transform()); //transform event upwards + ev = ev->xformed_by(ci->get_transform()); // Transform event upwards. ci = ci->get_parent_item(); } - - //_unblock(); } void Viewport::_gui_call_notification(Control *p_control, int p_what) { @@ -1706,12 +1307,10 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) { ci = ci->get_parent_item(); } - - //_unblock(); } -Control *Viewport::_gui_find_control(const Point2 &p_global) { - //aca va subwindows +Control *Viewport::gui_find_control(const Point2 &p_global) { + // Handle subwindows. _gui_sort_roots(); for (List<Control *>::Element *E = gui.roots.back(); E; E = E->prev()) { @@ -1743,8 +1342,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ } if (!p_node->is_visible()) { - //return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform); - return nullptr; //canvas item hidden, discard + return nullptr; // Canvas item hidden, discard. } Transform2D matrix = p_xform * p_node->get_transform(); @@ -1788,32 +1386,31 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ } bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check) { - { //attempt grab, try parent controls too - CanvasItem *ci = p_at_control; - while (ci) { - Control *control = Object::cast_to<Control>(ci); - if (control) { - if (control->can_drop_data(p_at_pos, gui.drag_data)) { - if (!p_just_check) { - control->drop_data(p_at_pos, gui.drag_data); - } - - return true; + // Attempt grab, try parent controls too. + CanvasItem *ci = p_at_control; + while (ci) { + Control *control = Object::cast_to<Control>(ci); + if (control) { + if (control->can_drop_data(p_at_pos, gui.drag_data)) { + if (!p_just_check) { + control->drop_data(p_at_pos, gui.drag_data); } - if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) { - break; - } + return true; } - p_at_pos = ci->get_transform().xform(p_at_pos); - - if (ci->is_set_as_top_level()) { + if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) { break; } + } + + p_at_pos = ci->get_transform().xform(p_at_pos); - ci = ci->get_parent_item(); + if (ci->is_set_as_top_level()) { + break; } + + ci = ci->get_parent_item(); } return false; @@ -1833,24 +1430,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (mb->is_pressed()) { Size2 pos = mpos; if (gui.mouse_focus_mask) { - //do not steal mouse focus and stuff while a focus mask exists - gui.mouse_focus_mask |= 1 << (mb->get_button_index() - 1); //add the button to the mask + // Do not steal mouse focus and stuff while a focus mask exists. + gui.mouse_focus_mask |= 1 << (mb->get_button_index() - 1); // Add the button to the mask. } else { - bool is_handled = false; - - if (is_handled) { - set_input_as_handled(); - return; - } - - //Matrix32 parent_xform; - - /* - if (data.parent_canvas_item) - parent_xform=data.parent_canvas_item->get_global_transform(); - */ - - gui.mouse_focus = _gui_find_control(pos); + gui.mouse_focus = gui_find_control(pos); gui.last_mouse_focus = gui.mouse_focus; if (!gui.mouse_focus) { @@ -1866,7 +1449,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } } - mb = mb->xformed_by(Transform2D()); // make a copy of the event + mb = mb->xformed_by(Transform2D()); // Make a copy of the event. mb->set_global_position(pos); @@ -1883,7 +1466,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } #endif - if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { //assign focus + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { // Assign focus. CanvasItem *ci = gui.mouse_focus; while (ci) { Control *control = Object::cast_to<Control>(ci); @@ -1915,7 +1498,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { set_input_as_handled(); if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) { - //alternate drop use (when using force_drag(), as proposed by #5342 + // Alternate drop use (when using force_drag(), as proposed by #5342). if (gui.mouse_focus) { _gui_drop(gui.mouse_focus, pos, false); } @@ -1929,7 +1512,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.drag_preview_id = ObjectID(); } _propagate_viewport_notification(this, NOTIFICATION_DRAG_END); - //change mouse accordingly + // Change mouse accordingly. } _gui_cancel_tooltip(); @@ -1949,26 +1532,28 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.dragging = false; gui.drag_mouse_over = nullptr; _propagate_viewport_notification(this, NOTIFICATION_DRAG_END); - //change mouse accordingly + // Change mouse accordingly. } - gui.mouse_focus_mask &= ~(1 << (mb->get_button_index() - 1)); //remove from mask + gui.mouse_focus_mask &= ~(1 << (mb->get_button_index() - 1)); // Remove from mask. if (!gui.mouse_focus) { - //release event is only sent if a mouse focus (previously pressed button) exists + // Release event is only sent if a mouse focus (previously pressed button) exists. return; } Size2 pos = mpos; - mb = mb->xformed_by(Transform2D()); //make a copy + mb = mb->xformed_by(Transform2D()); // Make a copy. mb->set_global_position(pos); pos = gui.focus_inv_xform.xform(pos); mb->set_position(pos); Control *mouse_focus = gui.mouse_focus; - //disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise + // Disable mouse focus if needed before calling input, + // this makes popups on mouse press event work better, + // as the release will never be received otherwise. if (gui.mouse_focus_mask == 0) { gui.mouse_focus = nullptr; gui.forced_mouse_focus = false; @@ -1978,11 +1563,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { _gui_call_input(mouse_focus, mb); } - /*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==MOUSE_BUTTON_LEFT) { - _propagate_viewport_notification(this,NOTIFICATION_DRAG_END); - gui.drag_data=Variant(); //always clear - }*/ - // In case the mouse was released after for example dragging a scrollbar, // check whether the current control is different from the stored one. If // it is different, rather than wait for it to be updated the next time the @@ -1991,7 +1571,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.mouse_focus) { over = gui.mouse_focus; } else { - over = _gui_find_control(mpos); + over = gui_find_control(mpos); } if (gui.mouse_focus_mask == 0 && over != gui.mouse_over) { @@ -2021,12 +1601,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Control *over = nullptr; - // D&D + // Drag & drop. if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) { gui.drag_accum += mm->get_relative(); float len = gui.drag_accum.length(); if (len > 10) { - { //attempt grab, try parent controls too + { // Attempt grab, try parent controls too. CanvasItem *ci = gui.mouse_focus; while (ci) { Control *control = Object::cast_to<Control>(ci); @@ -2074,7 +1654,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.mouse_focus) { over = gui.mouse_focus; } else { - over = _gui_find_control(mpos); + over = gui_find_control(mpos); } if (over != gui.mouse_over) { @@ -2099,14 +1679,14 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Vector2 speed = localizer.basis_xform(mm->get_speed()); Vector2 rel = localizer.basis_xform(mm->get_relative()); - mm = mm->xformed_by(Transform2D()); //make a copy + mm = mm->xformed_by(Transform2D()); // Make a copy. mm->set_global_position(mpos); mm->set_speed(speed); mm->set_relative(rel); if (mm->get_button_mask() == 0) { - //nothing pressed + // Nothing pressed. bool can_tooltip = true; @@ -2130,7 +1710,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { is_tooltip_shown = true; } } else { - is_tooltip_shown = true; //well, nothing to compare against, likely using custom control, so if it changes there is nothing we can do + is_tooltip_shown = true; // Nothing to compare against, likely using custom control, so if it changes there is nothing we can do. } } } else { @@ -2139,9 +1719,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } if (can_tooltip && !is_tooltip_shown) { + if (gui.tooltip_timer.is_valid()) { + gui.tooltip_timer->release_connections(); + gui.tooltip_timer = Ref<SceneTreeTimer>(); + } gui.tooltip_control = over; gui.tooltip_pos = over->get_screen_transform().xform(pos); - gui.tooltip_timer = gui.tooltip_delay; + gui.tooltip_timer = get_tree()->create_timer(gui.tooltip_delay); + gui.tooltip_timer->set_ignore_time_scale(true); + gui.tooltip_timer->connect("timeout", callable_mp(this, &Viewport::_gui_show_tooltip)); } } @@ -2181,7 +1767,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } if (gui.drag_data.get_type() != Variant::NIL) { - //handle dragandrop + // Handle drag & drop. Control *drag_preview = _gui_get_drag_preview(); if (drag_preview) { @@ -2191,9 +1777,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.drag_mouse_over = over; gui.drag_mouse_over_pos = Vector2(); - //find the window this is above of - - //see if there is an embedder + // Find the window this is above of. + // See if there is an embedder. Viewport *embedder = nullptr; Vector2 viewport_pos; @@ -2201,7 +1786,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { embedder = this; viewport_pos = mpos; } else { - //not an embedder, but may be a subwindow of an embedder + // Not an embedder, but may be a subwindow of an embedder. Window *w = Object::cast_to<Window>(this); if (w) { if (w->is_embedded()) { @@ -2209,7 +1794,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Transform2D ai = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse(); - viewport_pos = ai.xform(mpos) + w->get_position(); //to parent coords + viewport_pos = ai.xform(mpos) + w->get_position(); // To parent coords. } } } @@ -2217,13 +1802,13 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Viewport *viewport_under = nullptr; if (embedder) { - //use embedder logic + // Use embedder logic. for (int i = embedder->gui.sub_windows.size() - 1; i >= 0; i--) { Window *sw = embedder->gui.sub_windows[i].window; Rect2 swrect = Rect2i(sw->get_position(), sw->get_size()); if (!sw->get_flag(Window::FLAG_BORDERLESS)) { - int title_height = sw->get_theme_constant("title_height"); + int title_height = sw->get_theme_constant(SNAME("title_height")); swrect.position.y -= title_height; swrect.size.y += title_height; } @@ -2235,11 +1820,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } if (!viewport_under) { - //not in a subwindow, likely in embedder + // Not in a subwindow, likely in embedder. viewport_under = embedder; } } else { - //use displayserver logic + // Use DisplayServer logic. Vector2i screen_mouse_pos = DisplayServer::get_singleton()->mouse_get_position(); DisplayServer::WindowID window_id = DisplayServer::get_singleton()->get_window_at_screen_position(screen_mouse_pos); @@ -2247,7 +1832,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (window_id != DisplayServer::INVALID_WINDOW_ID) { ObjectID object_under = DisplayServer::get_singleton()->window_get_attached_instance_id(window_id); - if (object_under != ObjectID()) { //fetch window + if (object_under != ObjectID()) { // Fetch window. Window *w = Object::cast_to<Window>(ObjectDB::get_instance(object_under)); if (w) { viewport_under = w; @@ -2260,8 +1845,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (viewport_under) { Transform2D ai = (viewport_under->get_final_transform().affine_inverse() * viewport_under->_get_input_pre_xform()); viewport_pos = ai.xform(viewport_pos); - //find control under at pos - gui.drag_mouse_over = viewport_under->_gui_find_control(viewport_pos); + // Find control under at position. + gui.drag_mouse_over = viewport_under->gui_find_control(viewport_pos); if (gui.drag_mouse_over) { Transform2D localizer = gui.drag_mouse_over->get_global_transform_with_canvas().affine_inverse(); gui.drag_mouse_over_pos = localizer.xform(viewport_pos); @@ -2289,10 +1874,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (touch_event.is_valid()) { Size2 pos = touch_event->get_position(); if (touch_event->is_pressed()) { - Control *over = _gui_find_control(pos); + Control *over = gui_find_control(pos); if (over) { if (over->can_process()) { - touch_event = touch_event->xformed_by(Transform2D()); //make a copy + touch_event = touch_event->xformed_by(Transform2D()); // Make a copy. if (over == gui.mouse_focus) { pos = gui.focus_inv_xform.xform(pos); } else { @@ -2306,7 +1891,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } } else if (touch_event->get_index() == 0 && gui.last_mouse_focus) { if (gui.last_mouse_focus->can_process()) { - touch_event = touch_event->xformed_by(Transform2D()); //make a copy + touch_event = touch_event->xformed_by(Transform2D()); // Make a copy. touch_event->set_position(gui.focus_inv_xform.xform(pos)); _gui_call_input(gui.last_mouse_focus, touch_event); @@ -2324,10 +1909,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Size2 pos = gesture_event->get_position(); - Control *over = _gui_find_control(pos); + Control *over = gui_find_control(pos); if (over) { if (over->can_process()) { - gesture_event = gesture_event->xformed_by(Transform2D()); //make a copy + gesture_event = gesture_event->xformed_by(Transform2D()); // Make a copy. if (over == gui.mouse_focus) { pos = gui.focus_inv_xform.xform(pos); } else { @@ -2345,7 +1930,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (drag_event.is_valid()) { Control *over = gui.mouse_focus; if (!over) { - over = _gui_find_control(drag_event->get_position()); + over = gui_find_control(drag_event->get_position()); } if (over) { if (over->can_process()) { @@ -2354,7 +1939,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Vector2 speed = localizer.basis_xform(drag_event->get_speed()); Vector2 rel = localizer.basis_xform(drag_event->get_relative()); - drag_event = drag_event->xformed_by(Transform2D()); //make a copy + drag_event = drag_event->xformed_by(Transform2D()); // Make a copy. drag_event->set_speed(speed); drag_event->set_relative(rel); @@ -2376,10 +1961,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.key_focus) { gui.key_event_accepted = false; if (gui.key_focus->can_process()) { - gui.key_focus->call(SceneStringNames::get_singleton()->_gui_input, p_event); - if (gui.key_focus) { //maybe lost it - gui.key_focus->emit_signal(SceneStringNames::get_singleton()->gui_input, p_event); - } + gui.key_focus->_call_gui_input(p_event); } if (gui.key_event_accepted) { @@ -2388,12 +1970,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } } - Control *from = gui.key_focus ? gui.key_focus : nullptr; //hmm + Control *from = gui.key_focus ? gui.key_focus : nullptr; - //keyboard focus - //if (from && p_event->is_pressed() && !p_event->is_alt_pressed() && !p_event->is_meta_pressed() && !p_event->key->is_command_pressed()) { + // Keyboard focus. Ref<InputEventKey> k = p_event; - //need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/right/etc> is handled here when it shouldn't be. + // Need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/right/etc> is handled here when it shouldn't be. bool mods = k.is_valid() && (k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_shift_pressed() || k->is_meta_pressed()); if (from && p_event->is_pressed()) { @@ -2464,7 +2045,7 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) { } p_control->set_as_top_level(true); p_control->set_position(gui.last_mouse_pos); - p_base->get_root_parent_control()->add_child(p_control); //add as child of viewport + p_base->get_root_parent_control()->add_child(p_control); // Add as child of viewport. p_control->raise(); gui.drag_preview_id = p_control->get_instance_id(); @@ -2566,13 +2147,13 @@ bool Viewport::_gui_control_has_focus(const Control *p_control) { } void Viewport::_gui_control_grab_focus(Control *p_control) { - //no need for change if (gui.key_focus && gui.key_focus == p_control) { + // No need for change. return; } get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "_viewports", "_gui_remove_focus_for_window", (Node *)get_base_window()); gui.key_focus = p_control; - emit_signal("gui_focus_changed", p_control); + emit_signal(SNAME("gui_focus_changed"), p_control); p_control->notification(Control::NOTIFICATION_FOCUS_ENTER); p_control->update(); } @@ -2599,7 +2180,7 @@ void Viewport::_drop_mouse_focus() { mb->set_global_position(c->get_local_mouse_position()); mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(false); - c->call(SceneStringNames::get_singleton()->_gui_input, mb); + c->_call_gui_input(mb); } } } @@ -2607,20 +2188,41 @@ void Viewport::_drop_mouse_focus() { void Viewport::_drop_physics_mouseover(bool p_paused_only) { physics_has_last_mousepos = false; + _cleanup_mouseover_colliders(true, p_paused_only); + +#ifndef _3D_DISABLED + if (physics_object_over.is_valid()) { + CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over)); + if (co) { + if (!(p_paused_only && co->can_process())) { + co->_mouse_exit(); + physics_object_over = ObjectID(); + physics_object_capture = ObjectID(); + } + } + } +#endif // _3D_DISABLED +} + +void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference) { List<Map<ObjectID, uint64_t>::Element *> to_erase; for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) { + if (!p_clean_all_frames && E->get() == p_frame_reference) { + continue; + } + Object *o = ObjectDB::get_instance(E->key()); if (o) { CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); if (co) { - if (p_paused_only && co->can_process()) { + if (p_clean_all_frames && p_paused_only && co->can_process()) { continue; } co->_mouse_exit(); - to_erase.push_back(E); } } + to_erase.push_back(E); } while (to_erase.size()) { @@ -2628,18 +2230,31 @@ void Viewport::_drop_physics_mouseover(bool p_paused_only) { to_erase.pop_front(); } -#ifndef _3D_DISABLED - if (physics_object_over.is_valid()) { - CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over)); - if (co) { - if (!(p_paused_only && co->can_process())) { - co->_mouse_exit(); - physics_object_over = ObjectID(); - physics_object_capture = ObjectID(); + // Per-shape. + List<Map<Pair<ObjectID, int>, uint64_t, PairSort<ObjectID, int>>::Element *> shapes_to_erase; + + for (Map<Pair<ObjectID, int>, uint64_t, PairSort<ObjectID, int>>::Element *E = physics_2d_shape_mouseover.front(); E; E = E->next()) { + if (!p_clean_all_frames && E->get() == p_frame_reference) { + continue; + } + + Object *o = ObjectDB::get_instance(E->key().first); + if (o) { + CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); + if (co) { + if (p_clean_all_frames && p_paused_only && co->can_process()) { + continue; + } + co->_mouse_shape_exit(E->key().second); } } + shapes_to_erase.push_back(E); + } + + while (shapes_to_erase.size()) { + physics_2d_shape_mouseover.erase(shapes_to_erase.front()->get()); + shapes_to_erase.pop_front(); } -#endif } Control *Viewport::_gui_get_focus_owner() { @@ -2648,13 +2263,13 @@ Control *Viewport::_gui_get_focus_owner() { void Viewport::_gui_grab_click_focus(Control *p_control) { gui.mouse_click_grabber = p_control; - call_deferred("_post_gui_grab_click_focus"); + call_deferred(SNAME("_post_gui_grab_click_focus")); } void Viewport::_post_gui_grab_click_focus() { Control *focus_grabber = gui.mouse_click_grabber; if (!focus_grabber) { - // Redundant grab requests were made + // Redundant grab requests were made. return; } gui.mouse_click_grabber = nullptr; @@ -2672,12 +2287,12 @@ void Viewport::_post_gui_grab_click_focus() { Ref<InputEventMouseButton> mb; mb.instantiate(); - //send unclick + // Send unclick. mb->set_position(click); mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(false); - gui.mouse_focus->call(SceneStringNames::get_singleton()->_gui_input, mb); + gui.mouse_focus->_call_gui_input(mb); } } @@ -2690,12 +2305,12 @@ void Viewport::_post_gui_grab_click_focus() { Ref<InputEventMouseButton> mb; mb.instantiate(); - //send click + // Send click. mb->set_position(click); mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(true); - gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb); + MessageQueue::get_singleton()->push_callable(callable_mp(gui.mouse_focus, &Control::_call_gui_input), mb); } } } @@ -2703,9 +2318,9 @@ void Viewport::_post_gui_grab_click_focus() { /////////////////////////////// -void Viewport::input_text(const String &p_text) { +void Viewport::push_text_input(const String &p_text) { if (gui.subwindow_focused) { - gui.subwindow_focused->input_text(p_text); + gui.subwindow_focused->push_text_input(p_text); return; } @@ -2721,19 +2336,19 @@ Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subw Rect2i r = Rect2i(p_subwindow->get_position(), p_subwindow->get_size()); - int title_height = p_subwindow->get_theme_constant("title_height"); + int title_height = p_subwindow->get_theme_constant(SNAME("title_height")); r.position.y -= title_height; r.size.y += title_height; if (r.has_point(p_point)) { - return SUB_WINDOW_RESIZE_DISABLED; //it's inside, so no resize + return SUB_WINDOW_RESIZE_DISABLED; // It's inside, so no resize. } int dist_x = p_point.x < r.position.x ? (p_point.x - r.position.x) : (p_point.x > (r.position.x + r.size.x) ? (p_point.x - (r.position.x + r.size.x)) : 0); int dist_y = p_point.y < r.position.y ? (p_point.y - r.position.y) : (p_point.y > (r.position.y + r.size.y) ? (p_point.y - (r.position.y + r.size.y)) : 0); - int limit = p_subwindow->get_theme_constant("resize_margin"); + int limit = p_subwindow->get_theme_constant(SNAME("resize_margin")); if (ABS(dist_x) > limit) { return SUB_WINDOW_RESIZE_DISABLED; @@ -2786,12 +2401,12 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) { if (gui.subwindow_drag_close_rect.has_point(mb->get_position())) { - //close window + // Close window. gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST); } } gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; - if (gui.subwindow_focused != nullptr) { //may have been erased + if (gui.subwindow_focused != nullptr) { // May have been erased. _sub_window_update(gui.subwindow_focused); } } @@ -2815,7 +2430,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { new_rect.position.x = 0; } - int title_height = gui.subwindow_focused->get_flag(Window::FLAG_BORDERLESS) ? 0 : gui.subwindow_focused->get_theme_constant("title_height"); + int title_height = gui.subwindow_focused->get_flag(Window::FLAG_BORDERLESS) ? 0 : gui.subwindow_focused->get_theme_constant(SNAME("title_height")); if (new_rect.position.y < title_height) { new_rect.position.y = title_height; @@ -2898,28 +2513,28 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { gui.subwindow_focused->_rect_changed_callback(r); } - if (gui.subwindow_focused) { //may have been erased + if (gui.subwindow_focused) { // May have been erased. _sub_window_update(gui.subwindow_focused); } } - return true; //handled + return true; // Handled. } Ref<InputEventMouseButton> mb = p_event; - //if the event is a mouse button, we need to check whether another window was clicked + // If the event is a mouse button, we need to check whether another window was clicked. if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { bool click_on_window = false; for (int i = gui.sub_windows.size() - 1; i >= 0; i--) { SubWindow &sw = gui.sub_windows.write[i]; - //clicked inside window? + // Clicked inside window? Rect2i r = Rect2i(sw.window->get_position(), sw.window->get_size()); if (!sw.window->get_flag(Window::FLAG_BORDERLESS)) { - //check top bar - int title_height = sw.window->get_theme_constant("title_height"); + // Check top bar. + int title_height = sw.window->get_theme_constant(SNAME("title_height")); Rect2i title_bar = r; title_bar.position.y -= title_height; title_bar.size.y = title_height; @@ -2927,22 +2542,22 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { if (title_bar.has_point(mb->get_position())) { click_on_window = true; - int close_h_ofs = sw.window->get_theme_constant("close_h_ofs"); - int close_v_ofs = sw.window->get_theme_constant("close_v_ofs"); - Ref<Texture2D> close_icon = sw.window->get_theme_icon("close"); + int close_h_ofs = sw.window->get_theme_constant(SNAME("close_h_ofs")); + int close_v_ofs = sw.window->get_theme_constant(SNAME("close_v_ofs")); + Ref<Texture2D> close_icon = sw.window->get_theme_icon(SNAME("close")); Rect2 close_rect; close_rect.position = Vector2(r.position.x + r.size.x - close_v_ofs, r.position.y - close_h_ofs); close_rect.size = close_icon->get_size(); if (gui.subwindow_focused != sw.window) { - //refocus + // Refocus. _sub_window_grab_focus(sw.window); } if (close_rect.has_point(mb->get_position())) { gui.subwindow_drag = SUB_WINDOW_DRAG_CLOSE; - gui.subwindow_drag_close_inside = true; //starts inside + gui.subwindow_drag_close_inside = true; // Starts inside. gui.subwindow_drag_close_rect = close_rect; } else { gui.subwindow_drag = SUB_WINDOW_DRAG_MOVE; @@ -2963,9 +2578,9 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { } } if (!click_on_window && r.has_point(mb->get_position())) { - //clicked, see if it needs to fetch focus + // Clicked, see if it needs to fetch focus. if (gui.subwindow_focused != sw.window) { - //refocus + // Refocus. _sub_window_grab_focus(sw.window); } @@ -2978,7 +2593,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { } if (!click_on_window && gui.subwindow_focused) { - //no window found and clicked, remove focus + // No window found and clicked, remove focus. _sub_window_grab_focus(nullptr); } } @@ -3002,13 +2617,13 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]); - return true; //reserved for showing the resize cursor + return true; // Reserved for showing the resize cursor. } } } if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) { - return true; // dragging, don't pass the event + return true; // Dragging, don't pass the event. } if (!gui.subwindow_focused) { @@ -3025,7 +2640,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { return true; } -void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) { +void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) { ERR_FAIL_COND(!is_inside_tree()); if (disable_input) { @@ -3055,7 +2670,7 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) { } if (!is_input_handled()) { - get_tree()->_call_input_pause(input_group, "_input", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input + get_tree()->_call_input_pause(input_group, SceneTree::CALL_INPUT_TYPE_INPUT, ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input } if (!is_input_handled()) { @@ -3063,12 +2678,12 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) { } event_count++; - //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",ev); //special one for GUI, as controls use their own process check } -void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) { +void Viewport::push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) { ERR_FAIL_COND(p_event.is_null()); ERR_FAIL_COND(!is_inside_tree()); + local_input_handled = false; if (disable_input || !_can_consume_input_events()) { return; @@ -3085,12 +2700,12 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor ev = p_event; } - // Unhandled Input - get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", ev, this); + // Unhandled Input. + get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, ev, this); - // Unhandled key Input - used for performance reasons - This is called a lot less then _unhandled_input since it ignores MouseMotion, etc - if (!is_input_handled() && Object::cast_to<InputEventKey>(*ev) != nullptr) { - get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", ev, this); + // Unhandled key Input - used for performance reasons - This is called a lot less than _unhandled_input since it ignores MouseMotion, etc. + if (!is_input_handled() && (Object::cast_to<InputEventKey>(*ev) != nullptr || Object::cast_to<InputEventShortcut>(*ev) != nullptr)) { + get_tree()->_call_input_pause(unhandled_key_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT, ev, this); } if (physics_object_picking && !is_input_handled()) { @@ -3099,7 +2714,7 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor Object::cast_to<InputEventMouseMotion>(*ev) || Object::cast_to<InputEventScreenDrag>(*ev) || Object::cast_to<InputEventScreenTouch>(*ev) || - Object::cast_to<InputEventKey>(*ev) //to remember state + Object::cast_to<InputEventKey>(*ev) // To remember state. )) { physics_picking_events.push_back(ev); @@ -3107,48 +2722,15 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor } } -void Viewport::set_use_own_world_3d(bool p_world_3d) { - if (p_world_3d == own_world_3d.is_valid()) { - return; - } - - if (is_inside_tree()) { - _propagate_exit_world(this); - } - - if (!p_world_3d) { - own_world_3d = Ref<World3D>(); - if (world_3d.is_valid()) { - world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); - } - } else { - if (world_3d.is_valid()) { - own_world_3d = world_3d->duplicate(); - world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); - } else { - own_world_3d = Ref<World3D>(memnew(World3D)); - } - } - - if (is_inside_tree()) { - _propagate_enter_world(this); - } - - if (is_inside_tree()) { - RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario()); - } - - _update_listener(); -} - -bool Viewport::is_using_own_world_3d() const { - return own_world_3d.is_valid(); -} - void Viewport::set_physics_object_picking(bool p_enable) { physics_object_picking = p_enable; - if (!physics_object_picking) { + if (physics_object_picking) { + add_to_group("_picking_viewports"); + } else { physics_picking_events.clear(); + if (is_in_group("_picking_viewports")) { + remove_from_group("_picking_viewports"); + } } } @@ -3178,10 +2760,6 @@ Variant Viewport::gui_get_drag_data() const { } TypedArray<String> Viewport::get_configuration_warnings() const { - /*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) { - return TTR("This viewport is not set as render target. If you intend for it to display its contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign its internal texture to some node for display."); - }*/ - TypedArray<String> warnings = Node::get_configuration_warnings(); if (size.x == 0 || size.y == 0) { @@ -3240,6 +2818,7 @@ void Viewport::set_lod_threshold(float p_pixels) { lod_threshold = p_pixels; RS::get_singleton()->viewport_set_lod_threshold(viewport, lod_threshold); } + float Viewport::get_lod_threshold() const { return lod_threshold; } @@ -3452,6 +3031,7 @@ void Viewport::set_sdf_oversize(SDFOversize p_sdf_oversize) { sdf_oversize = p_sdf_oversize; RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale)); } + Viewport::SDFOversize Viewport::get_sdf_oversize() const { return sdf_oversize; } @@ -3461,17 +3041,429 @@ void Viewport::set_sdf_scale(SDFScale p_sdf_scale) { sdf_scale = p_sdf_scale; RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale)); } + Viewport::SDFScale Viewport::get_sdf_scale() const { return sdf_scale; } +#ifndef _3D_DISABLED +Listener3D *Viewport::get_listener_3d() const { + return listener_3d; +} + +void Viewport::set_as_audio_listener_3d(bool p_enable) { + if (p_enable == audio_listener_3d) { + return; + } + + audio_listener_3d = p_enable; + _update_listener_3d(); +} + +bool Viewport::is_audio_listener_3d() const { + return audio_listener_3d; +} + +void Viewport::_update_listener_3d() { + if (AudioServer::get_singleton()) { + AudioServer::get_singleton()->notify_listener_changed(); + } +} + +void Viewport::_listener_transform_3d_changed_notify() { +} + +void Viewport::_listener_3d_set(Listener3D *p_listener) { + if (listener_3d == p_listener) { + return; + } + + listener_3d = p_listener; + + _update_listener_3d(); + _listener_transform_3d_changed_notify(); +} + +bool Viewport::_listener_3d_add(Listener3D *p_listener) { + listener_3d_set.insert(p_listener); + return listener_3d_set.size() == 1; +} + +void Viewport::_listener_3d_remove(Listener3D *p_listener) { + listener_3d_set.erase(p_listener); + if (listener_3d == p_listener) { + listener_3d = nullptr; + } +} + +void Viewport::_listener_3d_make_next_current(Listener3D *p_exclude) { + if (listener_3d_set.size() > 0) { + for (Set<Listener3D *>::Element *E = listener_3d_set.front(); E; E = E->next()) { + if (p_exclude == E->get()) { + continue; + } + if (!E->get()->is_inside_tree()) { + continue; + } + if (listener_3d != nullptr) { + return; + } + + E->get()->make_current(); + } + } else { + // Attempt to reset listener to the camera position. + if (camera_3d != nullptr) { + _update_listener_3d(); + _camera_3d_transform_changed_notify(); + } + } +} + +void Viewport::_collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) { + Transform3D object_transform = p_object->get_global_transform(); + Transform3D camera_transform = p_camera->get_global_transform(); + ObjectID id = p_object->get_instance_id(); + + // Avoid sending the fake event unnecessarily if nothing really changed in the context. + if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) { + Ref<InputEventMouseMotion> mm = p_input_event; + if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { + return; // Discarded. + } + } + p_object->_input_event_call(camera_3d, p_input_event, p_pos, p_normal, p_shape); + physics_last_object_transform = object_transform; + physics_last_camera_transform = camera_transform; + physics_last_id = id; +} + +Camera3D *Viewport::get_camera_3d() const { + return camera_3d; +} + +void Viewport::_camera_3d_transform_changed_notify() { +} + +void Viewport::_camera_3d_set(Camera3D *p_camera) { + if (camera_3d == p_camera) { + return; + } + + if (camera_3d) { + camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT); + } + + camera_3d = p_camera; + + if (!camera_3d_override) { + if (camera_3d) { + RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera()); + } else { + RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID()); + } + } + + if (camera_3d) { + camera_3d->notification(Camera3D::NOTIFICATION_BECAME_CURRENT); + } + + _update_listener_3d(); + _camera_3d_transform_changed_notify(); +} + +bool Viewport::_camera_3d_add(Camera3D *p_camera) { + camera_3d_set.insert(p_camera); + return camera_3d_set.size() == 1; +} + +void Viewport::_camera_3d_remove(Camera3D *p_camera) { + camera_3d_set.erase(p_camera); + if (camera_3d == p_camera) { + camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT); + camera_3d = nullptr; + } +} + +void Viewport::_camera_3d_make_next_current(Camera3D *p_exclude) { + for (Set<Camera3D *>::Element *E = camera_3d_set.front(); E; E = E->next()) { + if (p_exclude == E->get()) { + continue; + } + if (!E->get()->is_inside_tree()) { + continue; + } + if (camera_3d != nullptr) { + return; + } + + E->get()->make_current(); + } +} + +void Viewport::enable_camera_3d_override(bool p_enable) { + if (p_enable == camera_3d_override) { + return; + } + + if (p_enable) { + camera_3d_override.rid = RenderingServer::get_singleton()->camera_create(); + } else { + RenderingServer::get_singleton()->free(camera_3d_override.rid); + camera_3d_override.rid = RID(); + } + + if (p_enable) { + RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d_override.rid); + } else if (camera_3d) { + RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera()); + } else { + RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID()); + } +} + +void Viewport::set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) { + if (camera_3d_override) { + if (camera_3d_override.fov == p_fovy_degrees && camera_3d_override.z_near == p_z_near && + camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_PERSPECTIVE) { + return; + } + + camera_3d_override.fov = p_fovy_degrees; + camera_3d_override.z_near = p_z_near; + camera_3d_override.z_far = p_z_far; + camera_3d_override.projection = Camera3DOverrideData::PROJECTION_PERSPECTIVE; + + RenderingServer::get_singleton()->camera_set_perspective(camera_3d_override.rid, camera_3d_override.fov, camera_3d_override.z_near, camera_3d_override.z_far); + } +} + +void Viewport::set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) { + if (camera_3d_override) { + if (camera_3d_override.size == p_size && camera_3d_override.z_near == p_z_near && + camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) { + return; + } + + camera_3d_override.size = p_size; + camera_3d_override.z_near = p_z_near; + camera_3d_override.z_far = p_z_far; + camera_3d_override.projection = Camera3DOverrideData::PROJECTION_ORTHOGONAL; + + RenderingServer::get_singleton()->camera_set_orthogonal(camera_3d_override.rid, camera_3d_override.size, camera_3d_override.z_near, camera_3d_override.z_far); + } +} + +void Viewport::set_disable_3d(bool p_disable) { + disable_3d = p_disable; + RenderingServer::get_singleton()->viewport_set_disable_3d(viewport, disable_3d); +} + +bool Viewport::is_3d_disabled() const { + return disable_3d; +} + +bool Viewport::is_camera_3d_override_enabled() const { + return camera_3d_override; +} + +void Viewport::set_camera_3d_override_transform(const Transform3D &p_transform) { + if (camera_3d_override) { + camera_3d_override.transform = p_transform; + RenderingServer::get_singleton()->camera_set_transform(camera_3d_override.rid, p_transform); + } +} + +Transform3D Viewport::get_camera_3d_override_transform() const { + if (camera_3d_override) { + return camera_3d_override.transform; + } + + return Transform3D(); +} + +Ref<World3D> Viewport::get_world_3d() const { + return world_3d; +} + +Ref<World3D> Viewport::find_world_3d() const { + if (own_world_3d.is_valid()) { + return own_world_3d; + } else if (world_3d.is_valid()) { + return world_3d; + } else if (parent) { + return parent->find_world_3d(); + } else { + return Ref<World3D>(); + } +} + +void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) { + if (world_3d == p_world_3d) { + return; + } + + if (is_inside_tree()) { + _propagate_exit_world_3d(this); + } + + if (own_world_3d.is_valid() && world_3d.is_valid()) { + world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); + } + + world_3d = p_world_3d; + + if (own_world_3d.is_valid()) { + if (world_3d.is_valid()) { + own_world_3d = world_3d->duplicate(); + world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); + } else { + own_world_3d = Ref<World3D>(memnew(World3D)); + } + } + + if (is_inside_tree()) { + _propagate_enter_world_3d(this); + } + + if (is_inside_tree()) { + RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario()); + } + + _update_listener_3d(); +} + +void Viewport::_own_world_3d_changed() { + ERR_FAIL_COND(world_3d.is_null()); + ERR_FAIL_COND(own_world_3d.is_null()); + + if (is_inside_tree()) { + _propagate_exit_world_3d(this); + } + + own_world_3d = world_3d->duplicate(); + + if (is_inside_tree()) { + _propagate_enter_world_3d(this); + } + + if (is_inside_tree()) { + RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario()); + } + + _update_listener_3d(); +} + +void Viewport::set_use_own_world_3d(bool p_world_3d) { + if (p_world_3d == own_world_3d.is_valid()) { + return; + } + + if (is_inside_tree()) { + _propagate_exit_world_3d(this); + } + + if (!p_world_3d) { + own_world_3d = Ref<World3D>(); + if (world_3d.is_valid()) { + world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); + } + } else { + if (world_3d.is_valid()) { + own_world_3d = world_3d->duplicate(); + world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); + } else { + own_world_3d = Ref<World3D>(memnew(World3D)); + } + } + + if (is_inside_tree()) { + _propagate_enter_world_3d(this); + } + + if (is_inside_tree()) { + RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario()); + } + + _update_listener_3d(); +} + +bool Viewport::is_using_own_world_3d() const { + return own_world_3d.is_valid(); +} + +void Viewport::_propagate_enter_world_3d(Node *p_node) { + if (p_node != this) { + if (!p_node->is_inside_tree()) { //may not have entered scene yet + return; + } + + if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) { + p_node->notification(Node3D::NOTIFICATION_ENTER_WORLD); + } else { + Viewport *v = Object::cast_to<Viewport>(p_node); + if (v) { + if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) { + return; + } + } + } + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + _propagate_enter_world_3d(p_node->get_child(i)); + } +} + +void Viewport::_propagate_exit_world_3d(Node *p_node) { + if (p_node != this) { + if (!p_node->is_inside_tree()) { //may have exited scene already + return; + } + + if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) { + p_node->notification(Node3D::NOTIFICATION_EXIT_WORLD); + } else { + Viewport *v = Object::cast_to<Viewport>(p_node); + if (v) { + if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) { + return; + } + } + } + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + _propagate_exit_world_3d(p_node->get_child(i)); + } +} + +void Viewport::set_use_xr(bool p_use_xr) { + use_xr = p_use_xr; + + RS::get_singleton()->viewport_set_use_xr(viewport, use_xr); +} + +bool Viewport::is_using_xr() { + return use_xr; +} + +void Viewport::set_scale_3d(const Scale3D p_scale_3d) { + scale_3d = p_scale_3d; + + RS::get_singleton()->viewport_set_scale_3d(viewport, RS::ViewportScale3D(scale_3d)); +} + +Viewport::Scale3D Viewport::get_scale_3d() const { + return scale_3d; +} + +#endif // _3D_DISABLED + void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_world_2d", "world_2d"), &Viewport::set_world_2d); ClassDB::bind_method(D_METHOD("get_world_2d"), &Viewport::get_world_2d); ClassDB::bind_method(D_METHOD("find_world_2d"), &Viewport::find_world_2d); - ClassDB::bind_method(D_METHOD("set_world_3d", "world_3d"), &Viewport::set_world_3d); - ClassDB::bind_method(D_METHOD("get_world_3d"), &Viewport::get_world_3d); - ClassDB::bind_method(D_METHOD("find_world_3d"), &Viewport::find_world_3d); ClassDB::bind_method(D_METHOD("set_canvas_transform", "xform"), &Viewport::set_canvas_transform); ClassDB::bind_method(D_METHOD("get_canvas_transform"), &Viewport::get_canvas_transform); @@ -3501,33 +3493,20 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("get_render_info", "type", "info"), &Viewport::get_render_info); - ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr); - ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr); - ClassDB::bind_method(D_METHOD("get_texture"), &Viewport::get_texture); ClassDB::bind_method(D_METHOD("set_physics_object_picking", "enable"), &Viewport::set_physics_object_picking); ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking); ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid); - ClassDB::bind_method(D_METHOD("input_text", "text"), &Viewport::input_text); - ClassDB::bind_method(D_METHOD("input", "event", "in_local_coords"), &Viewport::input, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("unhandled_input", "event", "in_local_coords"), &Viewport::unhandled_input, DEFVAL(false)); - - 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_camera"), &Viewport::get_camera); - - ClassDB::bind_method(D_METHOD("set_as_audio_listener", "enable"), &Viewport::set_as_audio_listener); - ClassDB::bind_method(D_METHOD("is_audio_listener"), &Viewport::is_audio_listener); + ClassDB::bind_method(D_METHOD("push_text_input", "text"), &Viewport::push_text_input); + ClassDB::bind_method(D_METHOD("push_input", "event", "in_local_coords"), &Viewport::push_input, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("push_unhandled_input", "event", "in_local_coords"), &Viewport::push_unhandled_input, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_camera_2d"), &Viewport::get_camera_2d); 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("set_disable_3d", "disable"), &Viewport::set_disable_3d); - ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled); - ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position); ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse); @@ -3585,17 +3564,41 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking); +#ifndef _3D_DISABLED + ClassDB::bind_method(D_METHOD("set_world_3d", "world_3d"), &Viewport::set_world_3d); + ClassDB::bind_method(D_METHOD("get_world_3d"), &Viewport::get_world_3d); + ClassDB::bind_method(D_METHOD("find_world_3d"), &Viewport::find_world_3d); + + 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_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); + + ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d); + ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled); + + ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr); + ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr); + + ClassDB::bind_method(D_METHOD("set_scale_3d", "scale"), &Viewport::set_scale_3d); + ClassDB::bind_method(D_METHOD("get_scale_3d"), &Viewport::get_scale_3d); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "scale_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled,75%,50%,33%,25%")), "set_scale_3d", "get_scale_3d"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener_3d", "is_audio_listener_3d"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d"); +#endif // _3D_DISABLED ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", PROPERTY_USAGE_NONE), "set_world_2d", "get_world_2d"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled"); ADD_GROUP("Rendering", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)"), "set_msaa", "get_msaa"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa", "get_msaa"); ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling"); @@ -3606,7 +3609,6 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat"); ADD_GROUP("Audio Listener", "audio_listener_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_2d"), "set_as_audio_listener_2d", "is_audio_listener_2d"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener", "is_audio_listener"); ADD_GROUP("Physics", "physics_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking"), "set_physics_object_picking", "get_physics_object_picking"); ADD_GROUP("GUI", "gui_"); @@ -3629,6 +3631,12 @@ void Viewport::_bind_methods() { ADD_SIGNAL(MethodInfo("size_changed")); ADD_SIGNAL(MethodInfo("gui_focus_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); + BIND_ENUM_CONSTANT(SCALE_3D_DISABLED); + BIND_ENUM_CONSTANT(SCALE_3D_75_PERCENT); + BIND_ENUM_CONSTANT(SCALE_3D_50_PERCENT); + BIND_ENUM_CONSTANT(SCALE_3D_33_PERCENT); + BIND_ENUM_CONSTANT(SCALE_3D_25_PERCENT); + BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED); BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_1); BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_4); @@ -3642,7 +3650,6 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(MSAA_2X); BIND_ENUM_CONSTANT(MSAA_4X); BIND_ENUM_CONSTANT(MSAA_8X); - BIND_ENUM_CONSTANT(MSAA_16X); BIND_ENUM_CONSTANT(MSAA_MAX); BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_DISABLED); @@ -3717,10 +3724,8 @@ Viewport::Viewport() { viewport_textures.insert(default_texture.ptr()); default_texture->proxy = RS::get_singleton()->texture_proxy_create(texture_rid); - //internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create(); - canvas_layers.insert(nullptr); // This eases picking code (interpreted as the canvas of the Viewport) + canvas_layers.insert(nullptr); // This eases picking code (interpreted as the canvas of the Viewport). - //clear=true; set_shadow_atlas_size(shadow_atlas_size); for (int i = 0; i < 4; i++) { @@ -3743,11 +3748,16 @@ Viewport::Viewport() { gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5); ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers - set_sdf_oversize(sdf_oversize); //set to server +#ifndef _3D_DISABLED + int scale = GLOBAL_GET("rendering/3d/viewport/scale"); + set_scale_3d((Scale3D)scale); +#endif // _3D_DISABLED + + set_sdf_oversize(sdf_oversize); // Set to server. } Viewport::~Viewport() { - //erase itself from viewport textures + // Erase itself from viewport textures. for (Set<ViewportTexture *>::Element *E = viewport_textures.front(); E; E = E->next()) { E->get()->vp = nullptr; } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 0f3bb8707d..bfb52c4b98 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -31,24 +31,26 @@ #ifndef VIEWPORT_H #define VIEWPORT_H -#include "core/math/transform_2d.h" #include "scene/main/node.h" #include "scene/resources/texture.h" -#include "scene/resources/world_2d.h" -#include "servers/display_server.h" -#include "servers/rendering_server.h" +#ifndef _3D_DISABLED class Camera3D; -class Camera2D; +class CollisionObject3D; class Listener3D; -class Control; +class World3D; +#endif // _3D_DISABLED + +class Listener2D; +class Camera2D; class CanvasItem; class CanvasLayer; -class Panel; +class Control; class Label; -class Timer; +class SceneTreeTimer; class Viewport; -class CollisionObject3D; +class Window; +class World2D; class ViewportTexture : public Texture2D { GDCLASS(ViewportTexture, Texture2D); @@ -87,6 +89,14 @@ class Viewport : public Node { GDCLASS(Viewport, Node); public: + enum Scale3D { + SCALE_3D_DISABLED, + SCALE_3D_75_PERCENT, + SCALE_3D_50_PERCENT, + SCALE_3D_33_PERCENT, + SCALE_3D_25_PERCENT + }; + enum ShadowAtlasQuadrantSubdiv { SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED, SHADOW_ATLAS_QUADRANT_SUBDIV_1, @@ -103,7 +113,7 @@ public: MSAA_2X, MSAA_4X, MSAA_8X, - MSAA_16X, + // 16x MSAA is not supported due to its high cost and driver bugs. MSAA_MAX }; @@ -192,38 +202,14 @@ private: Viewport *parent = nullptr; - Listener3D *listener = nullptr; - Set<Listener3D *> listeners; - - struct CameraOverrideData { - Transform3D transform; - enum Projection { - PROJECTION_PERSPECTIVE, - PROJECTION_ORTHOGONAL - }; - Projection projection = Projection::PROJECTION_PERSPECTIVE; - float fov = 0.0; - float size = 0.0; - float z_near = 0.0; - float z_far = 0.0; - RID rid; - - operator bool() const { - return rid != RID(); - } - } camera_override; - - Camera3D *camera = nullptr; - Set<Camera3D *> cameras; + Listener2D *listener_2d = nullptr; + Camera2D *camera_2d = nullptr; Set<CanvasLayer *> canvas_layers; RID viewport; RID current_canvas; RID subwindow_canvas; - bool audio_listener = false; - RID internal_listener; - bool audio_listener_2d = false; RID internal_listener_2d; @@ -237,7 +223,6 @@ private: Size2i size = Size2i(512, 512); Size2i size_2d_override; bool size_allocated = false; - bool use_xr = false; RID contact_2d_debug; RID contact_3d_debug_multimesh; @@ -261,7 +246,7 @@ private: Transform3D physics_last_camera_transform; ObjectID physics_last_id; bool physics_has_last_mousepos = false; - Vector2 physics_last_mousepos = Vector2(Math_INF, Math_INF); + Vector2 physics_last_mousepos = Vector2(INFINITY, INFINITY); struct { bool alt = false; bool control = false; @@ -271,16 +256,17 @@ private: } physics_last_mouse_state; - void _collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape); - bool handle_input_locally = true; bool local_input_handled = false; + // Collider to frame Map<ObjectID, uint64_t> physics_2d_mouseover; + // Collider & shape to frame + Map<Pair<ObjectID, int>, uint64_t, PairSort<ObjectID, int>> physics_2d_shape_mouseover; + // Cleans up colliders corresponding to old frames or all of them. + void _cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference = 0); Ref<World2D> world_2d; - Ref<World3D> world_3d; - Ref<World3D> own_world_3d; Rect2i to_screen_rect; StringName input_group; @@ -288,13 +274,10 @@ private: StringName unhandled_input_group; StringName unhandled_key_input_group; - void _update_listener(); void _update_listener_2d(); bool disable_3d = false; - void _propagate_enter_world(Node *p_node); - void _propagate_exit_world(Node *p_node); void _propagate_viewport_notification(Node *p_node, int p_what); void _update_global_transform(); @@ -366,8 +349,8 @@ private: bool drag_attempted = false; Variant drag_data; ObjectID drag_preview_id; - float tooltip_timer = -1.0; - float tooltip_delay = 0.0; + Ref<SceneTreeTimer> tooltip_timer; + double tooltip_delay = 0.0; Transform2D focus_inv_xform; bool roots_order_dirty = false; List<Control *> roots; @@ -397,7 +380,6 @@ private: void _gui_call_notification(Control *p_control, int p_what); void _gui_sort_roots(); - Control *_gui_find_control(const Point2 &p_global); Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform); void _gui_input_event(Ref<InputEvent> p_event); @@ -436,19 +418,12 @@ private: bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check); - friend class Listener3D; - void _listener_transform_changed_notify(); - void _listener_set(Listener3D *p_listener); - bool _listener_add(Listener3D *p_listener); //true if first - void _listener_remove(Listener3D *p_listener); - void _listener_make_next_current(Listener3D *p_exclude); + friend class Listener2D; + void _listener_2d_set(Listener2D *p_listener); + void _listener_2d_remove(Listener2D *p_listener); - friend class Camera3D; - void _camera_transform_changed_notify(); - void _camera_set(Camera3D *p_camera); - bool _camera_add(Camera3D *p_camera); //true if first - void _camera_remove(Camera3D *p_camera); - void _camera_make_next_current(Camera3D *p_exclude); + friend class Camera2D; + void _camera_2d_set(Camera2D *p_camera_2d); friend class CanvasLayer; void _canvas_layer_add(CanvasLayer *p_canvas_layer); @@ -461,8 +436,6 @@ private: void _gui_set_root_order_dirty(); - void _own_world_3d_changed(); - friend class Window; void _sub_window_update_order(); @@ -490,37 +463,17 @@ protected: public: uint64_t get_processed_events_count() const { return event_count; } - Listener3D *get_listener() const; - Camera3D *get_camera() const; - - void enable_camera_override(bool p_enable); - bool is_camera_override_enabled() const; - - void set_camera_override_transform(const Transform3D &p_transform); - Transform3D get_camera_override_transform() const; - - void set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far); - void set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far); - - void set_as_audio_listener(bool p_enable); - bool is_audio_listener() const; - + Listener2D *get_listener_2d() const; + Camera2D *get_camera_2d() const; void set_as_audio_listener_2d(bool p_enable); bool is_audio_listener_2d() const; - void set_disable_3d(bool p_disable); - bool is_3d_disabled() const; - void update_canvas_items(); Rect2 get_visible_rect() const; RID get_viewport_rid() const; - void set_world_3d(const Ref<World3D> &p_world_3d); void set_world_2d(const Ref<World2D> &p_world_2d); - Ref<World3D> get_world_3d() const; - Ref<World3D> find_world_3d() const; - Ref<World2D> get_world_2d() const; Ref<World2D> find_world_2d() const; @@ -541,9 +494,6 @@ public: void set_transparent_background(bool p_enable); bool has_transparent_background() const; - void set_use_xr(bool p_use_xr); - bool is_using_xr(); - Ref<ViewportTexture> get_texture() const; void set_shadow_atlas_size(int p_size); @@ -573,12 +523,9 @@ public: Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const; Vector2 get_camera_rect_size() const; - void set_use_own_world_3d(bool p_world_3d); - bool is_using_own_world_3d() const; - - void input_text(const String &p_text); - void input(const Ref<InputEvent> &p_event, bool p_local_coords = false); - void unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false); + void push_text_input(const String &p_text); + void push_input(const Ref<InputEvent> &p_event, bool p_local_coords = false); + void push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false); void set_disable_input(bool p_disable); bool is_input_disabled() const; @@ -618,6 +565,8 @@ public: bool gui_is_dragging() const; + Control *gui_find_control(const Point2 &p_global); + void set_sdf_oversize(SDFOversize p_sdf_oversize); SDFOversize get_sdf_oversize() const; @@ -641,6 +590,84 @@ public: void pass_mouse_focus_to(Viewport *p_viewport, Control *p_control); +#ifndef _3D_DISABLED + bool use_xr = false; + Scale3D scale_3d = SCALE_3D_DISABLED; + friend class Listener3D; + Listener3D *listener_3d = nullptr; + Set<Listener3D *> listener_3d_set; + bool audio_listener_3d = false; + RID internal_listener_3d; + Listener3D *get_listener_3d() const; + void set_as_audio_listener_3d(bool p_enable); + bool is_audio_listener_3d() const; + void _update_listener_3d(); + void _listener_transform_3d_changed_notify(); + void _listener_3d_set(Listener3D *p_listener); + bool _listener_3d_add(Listener3D *p_listener); //true if first + void _listener_3d_remove(Listener3D *p_listener); + void _listener_3d_make_next_current(Listener3D *p_exclude); + + void _collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape); + + struct Camera3DOverrideData { + Transform3D transform; + enum Projection { + PROJECTION_PERSPECTIVE, + PROJECTION_ORTHOGONAL + }; + Projection projection = Projection::PROJECTION_PERSPECTIVE; + real_t fov = 0.0; + real_t size = 0.0; + real_t z_near = 0.0; + real_t z_far = 0.0; + RID rid; + + operator bool() const { + return rid != RID(); + } + } camera_3d_override; + + friend class Camera3D; + Camera3D *camera_3d = nullptr; + Set<Camera3D *> camera_3d_set; + Camera3D *get_camera_3d() const; + void _camera_3d_transform_changed_notify(); + void _camera_3d_set(Camera3D *p_camera); + bool _camera_3d_add(Camera3D *p_camera); //true if first + void _camera_3d_remove(Camera3D *p_camera); + void _camera_3d_make_next_current(Camera3D *p_exclude); + + void enable_camera_3d_override(bool p_enable); + bool is_camera_3d_override_enabled() const; + + void set_camera_3d_override_transform(const Transform3D &p_transform); + Transform3D get_camera_3d_override_transform() const; + + void set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far); + void set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far); + + void set_disable_3d(bool p_disable); + bool is_3d_disabled() const; + + Ref<World3D> world_3d; + Ref<World3D> own_world_3d; + void set_world_3d(const Ref<World3D> &p_world_3d); + Ref<World3D> get_world_3d() const; + Ref<World3D> find_world_3d() const; + void _own_world_3d_changed(); + void set_use_own_world_3d(bool p_world_3d); + bool is_using_own_world_3d() const; + void _propagate_enter_world_3d(Node *p_node); + void _propagate_exit_world_3d(Node *p_node); + + void set_use_xr(bool p_use_xr); + bool is_using_xr(); + + void set_scale_3d(const Scale3D p_scale_3d); + Scale3D get_scale_3d() const; +#endif // _3D_DISABLED + Viewport(); ~Viewport(); }; @@ -697,6 +724,7 @@ VARIANT_ENUM_CAST(SubViewport::UpdateMode); VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv); VARIANT_ENUM_CAST(Viewport::MSAA); VARIANT_ENUM_CAST(Viewport::ScreenSpaceAA); +VARIANT_ENUM_CAST(Viewport::Scale3D); VARIANT_ENUM_CAST(Viewport::DebugDraw); VARIANT_ENUM_CAST(Viewport::SDFScale); VARIANT_ENUM_CAST(Viewport::SDFOversize); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index cf2a6b2adf..ca5a3915d0 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -31,10 +31,8 @@ #include "window.h" #include "core/debugger/engine_debugger.h" -#include "core/os/keyboard.h" #include "core/string/translation.h" #include "scene/gui/control.h" -#include "scene/resources/font.h" #include "scene/scene_string_names.h" void Window::set_title(const String &p_title) { @@ -42,9 +40,8 @@ void Window::set_title(const String &p_title) { if (embedder) { embedder->_sub_window_update(this); - } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { - DisplayServer::get_singleton()->window_set_title(p_title, window_id); + DisplayServer::get_singleton()->window_set_title(atr(p_title), window_id); } } @@ -115,7 +112,7 @@ Size2i Window::get_max_size() const { void Window::set_min_size(const Size2i &p_min_size) { min_size = p_min_size; - if (window_id != DisplayServer::INVALID_WINDOW_ID) { + if (!wrap_controls && window_id != DisplayServer::INVALID_WINDOW_ID) { DisplayServer::get_singleton()->window_set_min_size(min_size, window_id); } _update_window_size(); @@ -227,12 +224,13 @@ void Window::_make_window() { } } - window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size)); + DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID); + window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size)); ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id); DisplayServer::get_singleton()->window_set_max_size(max_size, window_id); DisplayServer::get_singleton()->window_set_min_size(min_size, window_id); - DisplayServer::get_singleton()->window_set_title(tr(title), window_id); + DisplayServer::get_singleton()->window_set_title(atr(title), window_id); DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); _update_window_size(); @@ -302,7 +300,7 @@ void Window::_propagate_window_notification(Node *p_node, int p_notification) { Node *child = p_node->get_child(i); Window *window = Object::cast_to<Window>(child); if (window) { - break; + continue; } _propagate_window_notification(child, p_notification); } @@ -312,39 +310,39 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) { switch (p_event) { case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: { _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER); - emit_signal("mouse_entered"); + emit_signal(SNAME("mouse_entered")); DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape } break; case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: { _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT); - emit_signal("mouse_exited"); + emit_signal(SNAME("mouse_exited")); } break; case DisplayServer::WINDOW_EVENT_FOCUS_IN: { focused = true; _propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_IN); - emit_signal("focus_entered"); + emit_signal(SNAME("focus_entered")); } break; case DisplayServer::WINDOW_EVENT_FOCUS_OUT: { focused = false; _propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_OUT); - emit_signal("focus_exited"); + emit_signal(SNAME("focus_exited")); } break; case DisplayServer::WINDOW_EVENT_CLOSE_REQUEST: { if (exclusive_child != nullptr) { break; //has an exclusive child, can't get events until child is closed } _propagate_window_notification(this, NOTIFICATION_WM_CLOSE_REQUEST); - emit_signal("close_requested"); + emit_signal(SNAME("close_requested")); } break; case DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST: { _propagate_window_notification(this, NOTIFICATION_WM_GO_BACK_REQUEST); - emit_signal("go_back_requested"); + emit_signal(SNAME("go_back_requested")); } break; case DisplayServer::WINDOW_EVENT_DPI_CHANGE: { _update_viewport_size(); _propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE); - emit_signal("dpi_changed"); + emit_signal(SNAME("dpi_changed")); } break; } } @@ -541,6 +539,7 @@ void Window::_update_window_size() { embedder->_sub_window_update(this); } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { DisplayServer::get_singleton()->window_set_size(size, window_id); + DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id); } //update the viewport @@ -660,8 +659,8 @@ void Window::_update_viewport_size() { if (!use_font_oversampling) { font_oversampling = 1.0; } - if (TS->font_get_oversampling() != font_oversampling) { - TS->font_set_oversampling(font_oversampling); + if (TS->font_get_global_oversampling() != font_oversampling) { + TS->font_set_global_oversampling(font_oversampling); } } @@ -698,93 +697,98 @@ Viewport *Window::_get_embedder() const { } void Window::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - bool embedded = false; - { - embedder = _get_embedder(); - - if (embedder) { - embedded = true; - - if (!visible) { - embedder = nullptr; //not yet since not visible + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + bool embedded = false; + { + embedder = _get_embedder(); + + if (embedder) { + embedded = true; + + if (!visible) { + embedder = nullptr; //not yet since not visible + } } } - } - - if (embedded) { - //create as embedded - if (embedder) { - embedder->_sub_window_register(this); - RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); - _update_window_size(); - } - } else { - if (get_parent() == nullptr) { - //it's the root window! - visible = true; //always visible - window_id = DisplayServer::MAIN_WINDOW_ID; - DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); - _update_from_window(); - //since this window already exists (created on start), we must update pos and size from it - { - position = DisplayServer::get_singleton()->window_get_position(window_id); - size = DisplayServer::get_singleton()->window_get_size(window_id); + if (embedded) { + //create as embedded + if (embedder) { + embedder->_sub_window_register(this); + RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); + _update_window_size(); } - _update_viewport_size(); //then feed back to the viewport - _update_window_callbacks(); - RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE); + } else { - //create - if (visible) { - _make_window(); + if (get_parent() == nullptr) { + //it's the root window! + visible = true; //always visible + window_id = DisplayServer::MAIN_WINDOW_ID; + DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); + _update_from_window(); + //since this window already exists (created on start), we must update pos and size from it + { + position = DisplayServer::get_singleton()->window_get_position(window_id); + size = DisplayServer::get_singleton()->window_get_size(window_id); + } + _update_viewport_size(); //then feed back to the viewport + _update_window_callbacks(); + RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE); + } else { + //create + if (visible) { + _make_window(); + } } } - } - - if (transient) { - _make_transient(); - } - if (visible) { - notification(NOTIFICATION_VISIBILITY_CHANGED); - emit_signal(SceneStringNames::get_singleton()->visibility_changed); - RS::get_singleton()->viewport_set_active(get_viewport_rid(), true); - } - } - - if (p_what == NOTIFICATION_READY) { - if (wrap_controls) { - _update_child_controls(); - } - } - if (p_what == NOTIFICATION_TRANSLATION_CHANGED) { - child_controls_changed(); - } + if (transient) { + _make_transient(); + } + if (visible) { + notification(NOTIFICATION_VISIBILITY_CHANGED); + emit_signal(SceneStringNames::get_singleton()->visibility_changed); + RS::get_singleton()->viewport_set_active(get_viewport_rid(), true); + } + } break; + case NOTIFICATION_READY: { + if (wrap_controls) { + _update_child_controls(); + } + } break; + case NOTIFICATION_TRANSLATION_CHANGED: { + if (embedder) { + embedder->_sub_window_update(this); + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_title(atr(title), window_id); + } - if (p_what == NOTIFICATION_EXIT_TREE) { - if (transient) { - _clear_transient(); - } + child_controls_changed(); + } break; + case NOTIFICATION_EXIT_TREE: { + if (transient) { + _clear_transient(); + } - if (!is_embedded() && window_id != DisplayServer::INVALID_WINDOW_ID) { - if (window_id == DisplayServer::MAIN_WINDOW_ID) { - RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); - _update_window_callbacks(); + if (!is_embedded() && window_id != DisplayServer::INVALID_WINDOW_ID) { + if (window_id == DisplayServer::MAIN_WINDOW_ID) { + RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); + _update_window_callbacks(); + } else { + _clear_window(); + } } else { - _clear_window(); - } - } else { - if (embedder) { - embedder->_sub_window_remove(this); - embedder = nullptr; - RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); + if (embedder) { + embedder->_sub_window_remove(this); + embedder = nullptr; + RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); + } + _update_viewport_size(); //called by clear and make, which does not happen here } - _update_viewport_size(); //called by clear and make, which does not happen here - } - RS::get_singleton()->viewport_set_active(get_viewport_rid(), false); + RS::get_singleton()->viewport_set_active(get_viewport_rid(), false); + } break; } } @@ -880,7 +884,7 @@ void Window::child_controls_changed() { } updating_child_controls = true; - call_deferred("_update_child_controls"); + call_deferred(SNAME("_update_child_controls")); } bool Window::_can_consume_input_events() const { @@ -912,18 +916,18 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) { emit_signal(SceneStringNames::get_singleton()->window_input, p_ev); - input(p_ev); + push_input(p_ev); if (!is_input_handled()) { - unhandled_input(p_ev); + push_unhandled_input(p_ev); } } void Window::_window_input_text(const String &p_text) { - input_text(p_text); + push_text_input(p_text); } void Window::_window_drop_files(const Vector<String> &p_files) { - emit_signal("files_dropped", p_files, current_screen); + emit_signal(SNAME("files_dropped"), p_files, current_screen); } Viewport *Window::get_parent_viewport() const { @@ -1041,7 +1045,7 @@ void Window::popup_centered_ratio(float p_ratio) { } void Window::popup(const Rect2i &p_screen_rect) { - emit_signal("about_to_popup"); + emit_signal(SNAME("about_to_popup")); // Update window size to calculate the actual window size based on contents minimum size and minimum size. _update_window_size(); @@ -1169,23 +1173,24 @@ Ref<Theme> Window::get_theme() const { return theme; } -void Window::set_theme_custom_type(const StringName &p_theme_type) { - theme_custom_type = p_theme_type; +void Window::set_theme_type_variation(const StringName &p_theme_type) { + theme_type_variation = p_theme_type; Control::_propagate_theme_changed(this, theme_owner, theme_owner_window); } -StringName Window::get_theme_custom_type() const { - return theme_custom_type; +StringName Window::get_theme_type_variation() const { + return theme_type_variation; } void Window::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const { - if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_custom_type) { - if (theme_custom_type != StringName()) { - p_list->push_back(theme_custom_type); + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(theme_type_variation) != StringName()) { + Theme::get_project_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); + } else { + Theme::get_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); } - Theme::get_type_dependencies(get_class_name(), p_list); } else { - Theme::get_type_dependencies(p_theme_type, p_list); + Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list); } } @@ -1322,14 +1327,14 @@ bool Window::is_layout_rtl() const { if (parent) { return parent->is_layout_rtl(); } else { - if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) { + if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { return true; } String locale = TranslationServer::get_singleton()->get_tool_locale(); return TS->is_locale_right_to_left(locale); } } else if (layout_dir == LAYOUT_DIRECTION_LOCALE) { - if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) { + if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { return true; } String locale = TranslationServer::get_singleton()->get_tool_locale(); @@ -1339,6 +1344,48 @@ bool Window::is_layout_rtl() const { } } +void Window::set_auto_translate(bool p_enable) { + if (p_enable == auto_translate) { + return; + } + + auto_translate = p_enable; + + notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED); +} + +bool Window::is_auto_translating() const { + return auto_translate; +} + +void Window::_validate_property(PropertyInfo &property) const { + if (property.name == "theme_type_variation") { + List<StringName> names; + + // Only the default theme and the project theme are used for the list of options. + // This is an imposed limitation to simplify the logic needed to leverage those options. + Theme::get_default()->get_type_variation_list(get_class_name(), &names); + if (Theme::get_project_default().is_valid()) { + Theme::get_project_default()->get_type_variation_list(get_class_name(), &names); + } + names.sort_custom<StringName::AlphCompare>(); + + Vector<StringName> unique_names; + String hint_string; + for (const StringName &E : names) { + // Skip duplicate values. + if (unique_names.has(E)) { + continue; + } + + hint_string += String(E) + ","; + unique_names.append(E); + } + + property.hint_string = hint_string; + } +} + void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title); ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title); @@ -1416,8 +1463,8 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Window::set_theme); ClassDB::bind_method(D_METHOD("get_theme"), &Window::get_theme); - ClassDB::bind_method(D_METHOD("set_theme_custom_type", "theme_type"), &Window::set_theme_custom_type); - ClassDB::bind_method(D_METHOD("get_theme_custom_type"), &Window::get_theme_custom_type); + ClassDB::bind_method(D_METHOD("set_theme_type_variation", "theme_type"), &Window::set_theme_type_variation); + ClassDB::bind_method(D_METHOD("get_theme_type_variation"), &Window::get_theme_type_variation); ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "theme_type"), &Window::get_theme_icon, DEFVAL("")); ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "theme_type"), &Window::get_theme_stylebox, DEFVAL("")); @@ -1437,6 +1484,9 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction); ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl); + ClassDB::bind_method(D_METHOD("set_auto_translate", "enable"), &Window::set_auto_translate); + ClassDB::bind_method(D_METHOD("is_auto_translating"), &Window::is_auto_translating); + ClassDB::bind_method(D_METHOD("popup", "rect"), &Window::popup, DEFVAL(Rect2i())); ClassDB::bind_method(D_METHOD("popup_on_parent", "parent_rect"), &Window::popup_on_parent); ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Window::popup_centered_ratio, DEFVAL(0.8)); @@ -1447,7 +1497,8 @@ void Window::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_screen"), "set_current_screen", "get_current_screen"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen"), "set_current_screen", "get_current_screen"); + ADD_GROUP("Flags", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls"); @@ -1458,16 +1509,22 @@ void Window::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "always_on_top"), "set_flag", "get_flag", FLAG_ALWAYS_ON_TOP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_flag", "get_flag", FLAG_TRANSPARENT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS); + ADD_GROUP("Limits", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size"), "set_min_size", "get_min_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "max_size"), "set_max_size", "get_max_size"); + ADD_GROUP("Content Scale", "content_scale_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "content_scale_size"), "set_content_scale_size", "get_content_scale_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_mode", PROPERTY_HINT_ENUM, "Disabled,Canvas Items,Viewport"), "set_content_scale_mode", "get_content_scale_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_aspect", PROPERTY_HINT_ENUM, "Ignore,Keep,Keep Width,Keep Height,Expand"), "set_content_scale_aspect", "get_content_scale_aspect"); + 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_custom_type"), "set_theme_custom_type", "get_theme_custom_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation"); + + ADD_GROUP("Auto Translate", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating"); ADD_SIGNAL(MethodInfo("window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"))); diff --git a/scene/main/window.h b/scene/main/window.h index 494c386606..4f31d9cd1f 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -32,10 +32,12 @@ #define WINDOW_H #include "scene/main/viewport.h" -#include "scene/resources/theme.h" -#include "servers/display_server.h" class Control; +class Font; +class StyleBox; +class Theme; + class Window : public Viewport { GDCLASS(Window, Viewport) public: @@ -103,6 +105,8 @@ private: LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED; + bool auto_translate = true; + void _update_child_controls(); Size2i content_scale_size; @@ -130,7 +134,7 @@ private: Ref<Theme> theme; Control *theme_owner = nullptr; Window *theme_owner_window = nullptr; - StringName theme_custom_type; + StringName theme_type_variation; Viewport *embedder = nullptr; @@ -151,6 +155,7 @@ protected: virtual Size2 _get_contents_minimum_size() const; static void _bind_methods(); void _notification(int p_what); + virtual void _validate_property(PropertyInfo &property) const override; virtual void add_child_notify(Node *p_child) override; virtual void remove_child_notify(Node *p_child) override; @@ -242,8 +247,8 @@ public: void set_theme(const Ref<Theme> &p_theme); Ref<Theme> get_theme() const; - void set_theme_custom_type(const StringName &p_theme_type); - StringName get_theme_custom_type() const; + void set_theme_type_variation(const StringName &p_theme_type); + StringName get_theme_type_variation() const; _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const; Size2 get_contents_minimum_size() const; @@ -255,6 +260,10 @@ public: LayoutDirection get_layout_direction() const; bool is_layout_rtl() const; + void set_auto_translate(bool p_enable); + bool is_auto_translating() const; + _FORCE_INLINE_ String atr(const String p_string) const { return is_auto_translating() ? tr(p_string) : p_string; }; + Rect2i get_usable_parent_rect() const; Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_theme_type = StringName()) const; |