summaryrefslogtreecommitdiff
path: root/scene/main
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main')
-rw-r--r--scene/main/canvas_item.cpp111
-rw-r--r--scene/main/canvas_item.h42
-rw-r--r--scene/main/canvas_layer.cpp23
-rw-r--r--scene/main/canvas_layer.h4
-rw-r--r--scene/main/http_request.cpp114
-rw-r--r--scene/main/http_request.h2
-rw-r--r--scene/main/instance_placeholder.cpp2
-rw-r--r--scene/main/node.cpp613
-rw-r--r--scene/main/node.h78
-rw-r--r--scene/main/scene_tree.cpp216
-rw-r--r--scene/main/scene_tree.h29
-rw-r--r--scene/main/shader_globals_override.cpp29
-rw-r--r--scene/main/shader_globals_override.h2
-rw-r--r--scene/main/timer.cpp12
-rw-r--r--scene/main/viewport.cpp564
-rw-r--r--scene/main/viewport.h90
-rw-r--r--scene/main/window.cpp216
-rw-r--r--scene/main/window.h32
18 files changed, 1046 insertions, 1133 deletions
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 90bc99a941..5a12480577 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -128,24 +128,21 @@ void CanvasItemMaterial::_update_shader() {
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 += "uniform bool particles_anim_loop;\n\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 += " float h_frames = float(particles_anim_h_frames);\n";
+ code += " float v_frames = float(particles_anim_v_frames);\n";
+ code += " VERTEX.xy /= vec2(h_frames, v_frames);\n";
+ code += " float particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n";
+ code += " float particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
+ code += " if (!particles_anim_loop) {\n";
+ code += " particle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
+ code += " } else {\n";
+ code += " particle_frame = mod(particle_frame, particle_total_frames);\n";
+ code += " }";
+ code += " UV /= vec2(h_frames, v_frames);\n";
+ code += " UV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n";
code += "}\n";
}
@@ -239,7 +236,7 @@ bool CanvasItemMaterial::get_particles_anim_loop() const {
void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
if (property.name.begins_with("particles_anim_") && !particles_animation) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -271,7 +268,7 @@ void CanvasItemMaterial::_bind_methods() {
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,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
+ 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");
@@ -526,7 +523,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 +542,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 +588,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 +648,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) {
@@ -729,13 +726,13 @@ void CanvasItem::item_rect_changed(bool p_size_changed) {
emit_signal(SceneStringNames::get_singleton()->item_rect_changed);
}
-void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) {
+void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width);
}
-void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) {
+void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width, bool p_antialiased) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
Vector<Color> colors;
@@ -743,25 +740,25 @@ void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_co
RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width, p_antialiased);
}
-void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
+void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width, bool p_antialiased) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
}
-void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width, bool p_antialiased) {
+void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width, bool p_antialiased) {
Vector<Point2> points;
points.resize(p_point_count);
- const float delta_angle = p_end_angle - p_start_angle;
+ const real_t delta_angle = p_end_angle - p_start_angle;
for (int i = 0; i < p_point_count; i++) {
- float theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
+ real_t theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
}
draw_polyline(points, p_color, p_width, p_antialiased);
}
-void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
+void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
Vector<Color> colors;
@@ -769,13 +766,13 @@ void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_c
RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width);
}
-void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width);
}
-void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, float p_width) {
+void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
if (p_filled) {
@@ -787,7 +784,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
} else {
// Thick lines are offset depending on their width to avoid partial overlapping.
// Thin lines don't require an offset, so don't apply one in this case
- float offset;
+ real_t offset;
if (p_width >= 2) {
offset = p_width / 2.0;
} else {
@@ -821,7 +818,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
}
}
-void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) {
+void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
@@ -856,14 +853,14 @@ void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p
p_style_box->draw(canvas_item, p_rect);
}
-void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, float p_width) {
+void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width);
}
-void CanvasItem::draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale) {
+void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
Transform2D xform(p_rot, p_offset);
@@ -876,6 +873,17 @@ void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
}
+void CanvasItem::draw_animation_slice(double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) {
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, p_animation_length, p_slice_begin, p_slice_end, p_offset);
+}
+
+void CanvasItem::draw_end_animation() {
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, 1, 0, 2, 0);
+}
void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -907,19 +915,19 @@ void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Tex
RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid);
}
-void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_font.is_null());
p_font->draw_string(canvas_item, p_pos, p_text, p_align, p_width, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags);
}
-void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_font.is_null());
p_font->draw_multiline_string(canvas_item, p_pos, p_text, p_align, p_width, p_max_lines, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags);
}
-float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const {
+real_t CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const {
ERR_FAIL_COND_V_MSG(!drawing, 0.f, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND_V(p_font.is_null(), 0.f);
ERR_FAIL_COND_V(p_char.length() != 1, 0.f);
@@ -1159,6 +1167,8 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture"), &CanvasItem::draw_multimesh);
ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform, DEFVAL(0.0), DEFVAL(Size2(1.0, 1.0)));
ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix);
+ ClassDB::bind_method(D_METHOD("draw_animation_slice", "animation_length", "slice_begin", "slice_end", "offset"), &CanvasItem::draw_animation_slice, DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("draw_end_animation"), &CanvasItem::draw_end_animation);
ClassDB::bind_method(D_METHOD("get_transform"), &CanvasItem::get_transform);
ClassDB::bind_method(D_METHOD("get_global_transform"), &CanvasItem::get_global_transform);
ClassDB::bind_method(D_METHOD("get_global_transform_with_canvas"), &CanvasItem::get_global_transform_with_canvas);
@@ -1205,16 +1215,16 @@ void CanvasItem::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_on_top", "_is_on_top"); //compatibility
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
ADD_GROUP("Texture", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
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");
@@ -1414,7 +1424,7 @@ CanvasItem::~CanvasItem() {
///////////////////////////////////////////////////////////////////
void CanvasTexture::set_diffuse_texture(const Ref<Texture2D> &p_diffuse) {
- ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_diffuse.ptr()) != nullptr, "Cant self-assign a CanvasTexture");
+ ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_diffuse.ptr()) != nullptr, "Can't self-assign a CanvasTexture");
diffuse_texture = p_diffuse;
RID tex_rid = diffuse_texture.is_valid() ? diffuse_texture->get_rid() : RID();
@@ -1426,7 +1436,7 @@ Ref<Texture2D> CanvasTexture::get_diffuse_texture() const {
}
void CanvasTexture::set_normal_texture(const Ref<Texture2D> &p_normal) {
- ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_normal.ptr()) != nullptr, "Cant self-assign a CanvasTexture");
+ ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_normal.ptr()) != nullptr, "Can't self-assign a CanvasTexture");
normal_texture = p_normal;
RID tex_rid = normal_texture.is_valid() ? normal_texture->get_rid() : RID();
RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_NORMAL, tex_rid);
@@ -1436,11 +1446,12 @@ Ref<Texture2D> CanvasTexture::get_normal_texture() const {
}
void CanvasTexture::set_specular_texture(const Ref<Texture2D> &p_specular) {
- ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_specular.ptr()) != nullptr, "Cant self-assign a CanvasTexture");
+ ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_specular.ptr()) != nullptr, "Can't self-assign a CanvasTexture");
specular_texture = p_specular;
RID tex_rid = specular_texture.is_valid() ? specular_texture->get_rid() : RID();
RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_SPECULAR, tex_rid);
}
+
Ref<Texture2D> CanvasTexture::get_specular_texture() const {
return specular_texture;
}
@@ -1449,15 +1460,17 @@ void CanvasTexture::set_specular_color(const Color &p_color) {
specular = p_color;
RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
}
+
Color CanvasTexture::get_specular_color() const {
return specular;
}
-void CanvasTexture::set_specular_shininess(float p_shininess) {
+void CanvasTexture::set_specular_shininess(real_t p_shininess) {
shininess = p_shininess;
RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
}
-float CanvasTexture::get_specular_shininess() const {
+
+real_t CanvasTexture::get_specular_shininess() const {
return shininess;
}
@@ -1508,9 +1521,9 @@ bool CanvasTexture::has_alpha() const {
}
}
-Ref<Image> CanvasTexture::get_data() const {
+Ref<Image> CanvasTexture::get_image() const {
if (diffuse_texture.is_valid()) {
- return diffuse_texture->get_data();
+ return diffuse_texture->get_image();
} else {
return Ref<Image>();
}
@@ -1551,7 +1564,7 @@ void CanvasTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "specular_shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_specular_shininess", "get_specular_shininess");
ADD_GROUP("Texture", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index e22f93a7ea..f264764870 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -187,7 +187,7 @@ private:
mutable SelfList<Node> xform_change;
RID canvas_item;
- String group;
+ StringName group;
CanvasLayer *canvas_layer = nullptr;
@@ -290,8 +290,8 @@ public:
// Used to rotate the node
virtual bool _edit_use_rotation() const { return false; };
- virtual void _edit_set_rotation(float p_rotation) {}
- virtual float _edit_get_rotation() const { return 0.0; };
+ virtual void _edit_set_rotation(real_t p_rotation) {}
+ virtual real_t _edit_get_rotation() const { return 0.0; };
// Used to resize/move the node
virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
@@ -331,31 +331,33 @@ public:
/* DRAWING API */
- void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
- void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
- void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
- void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
- void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0);
- void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
- void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0);
- void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color);
+ void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0);
+ void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
+ void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0, bool p_antialiased = false);
+ void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
+ void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0);
+ void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0);
+ void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = 1.0);
+ void draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color);
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_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>(), float p_width = 1);
+ 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>());
void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());
void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1));
void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture);
- void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const;
+ void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+ void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+ real_t draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const;
- void draw_set_transform(const Point2 &p_offset, float p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0));
+ void draw_set_transform(const Point2 &p_offset, real_t p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0));
void draw_set_transform_matrix(const Transform2D &p_matrix);
+ void draw_animation_slice(double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset = 0);
+ void draw_end_animation();
static CanvasItem *get_current_item_drawn();
@@ -437,7 +439,7 @@ class CanvasTexture : public Texture2D {
Ref<Texture2D> normal_texture;
Ref<Texture2D> specular_texture;
Color specular = Color(1, 1, 1, 1);
- float shininess = 1.0;
+ real_t shininess = 1.0;
RID canvas_texture;
@@ -460,8 +462,8 @@ public:
void set_specular_color(const Color &p_color);
Color get_specular_color() const;
- void set_specular_shininess(float p_shininess);
- float get_specular_shininess() const;
+ void set_specular_shininess(real_t p_shininess);
+ real_t get_specular_shininess() const;
void set_texture_filter(CanvasItem::TextureFilter p_filter);
CanvasItem::TextureFilter get_texture_filter() const;
@@ -475,7 +477,7 @@ public:
virtual bool is_pixel_opaque(int p_x, int p_y) const override;
virtual bool has_alpha() const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
virtual RID get_rid() const override;
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 91daa08ff8..4540e42b4c 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -103,14 +103,6 @@ real_t CanvasLayer::get_rotation() const {
return rot;
}
-void CanvasLayer::set_rotation_degrees(real_t p_degrees) {
- set_rotation(Math::deg2rad(p_degrees));
-}
-
-real_t CanvasLayer::get_rotation_degrees() const {
- return Math::rad2deg(get_rotation());
-}
-
void CanvasLayer::set_scale(const Vector2 &p_scale) {
if (locrotscale_dirty) {
_update_locrotscale();
@@ -231,6 +223,7 @@ void CanvasLayer::set_follow_viewport(bool p_enable) {
follow_viewport = p_enable;
_update_follow_viewport();
+ notify_property_list_changed();
}
bool CanvasLayer::is_following_viewport() const {
@@ -257,6 +250,12 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) {
}
}
+void CanvasLayer::_validate_property(PropertyInfo &property) const {
+ if (!follow_viewport && property.name == "follow_viewport_scale") {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void CanvasLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer);
ClassDB::bind_method(D_METHOD("get_layer"), &CanvasLayer::get_layer);
@@ -270,9 +269,6 @@ void CanvasLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &CanvasLayer::set_rotation);
ClassDB::bind_method(D_METHOD("get_rotation"), &CanvasLayer::get_rotation);
- ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &CanvasLayer::set_rotation_degrees);
- ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &CanvasLayer::get_rotation_degrees);
-
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &CanvasLayer::set_scale);
ClassDB::bind_method(D_METHOD("get_scale"), &CanvasLayer::get_scale);
@@ -291,12 +287,11 @@ void CanvasLayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "layer", PROPERTY_HINT_RANGE, "-128,128,1"), "set_layer", "get_layer");
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
ADD_GROUP("", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport");
ADD_GROUP("Follow Viewport", "follow_viewport");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enable"), "set_follow_viewport", "is_following_viewport");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale");
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index 181d1dd659..5de1ebf18d 100644
--- a/scene/main/canvas_layer.h
+++ b/scene/main/canvas_layer.h
@@ -64,6 +64,7 @@ class CanvasLayer : public Node {
protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
public:
void set_layer(int p_xform);
@@ -78,9 +79,6 @@ public:
void set_rotation(real_t p_radians);
real_t get_rotation() const;
- void set_rotation_degrees(real_t p_degrees);
- real_t get_rotation_degrees() const;
-
void set_scale(const Size2 &p_scale);
Size2 get_scale() const;
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index ce7d6ef13c..f649380afa 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -40,9 +40,7 @@ Error HTTPRequest::_request() {
}
Error HTTPRequest::_parse_url(const String &p_url) {
- url = p_url;
use_ssl = false;
-
request_string = "";
port = 80;
request_sent = false;
@@ -52,35 +50,20 @@ Error HTTPRequest::_parse_url(const String &p_url) {
downloaded.set(0);
redirections = 0;
- String url_lower = url.to_lower();
- if (url_lower.begins_with("http://")) {
- url = url.substr(7, url.length() - 7);
- } else if (url_lower.begins_with("https://")) {
- url = url.substr(8, url.length() - 8);
+ String scheme;
+ Error err = p_url.parse_url(scheme, url, port, request_string);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing URL: " + p_url + ".");
+ if (scheme == "https://") {
use_ssl = true;
- port = 443;
- } else {
- ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL: " + url + ".");
+ } else if (scheme != "http://") {
+ ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Invalid URL scheme: " + scheme + ".");
}
-
- ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short: " + url + ".");
-
- int slash_pos = url.find("/");
-
- if (slash_pos != -1) {
- request_string = url.substr(slash_pos, url.length());
- url = url.substr(0, slash_pos);
- } else {
- request_string = "/";
+ if (port == 0) {
+ port = use_ssl ? 443 : 80;
}
-
- int colon_pos = url.find(":");
- if (colon_pos != -1) {
- port = url.substr(colon_pos + 1, url.length()).to_int();
- url = url.substr(0, colon_pos);
- ERR_FAIL_COND_V(port < 1 || port > 65535, ERR_INVALID_PARAMETER);
+ if (request_string.is_empty()) {
+ request_string = "/";
}
-
return OK;
}
@@ -123,7 +106,7 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
size_t len = charstr.length();
raw_data.resize(len);
uint8_t *w = raw_data.ptrw();
- copymem(w, charstr.ptr(), len);
+ memcpy(w, charstr.ptr(), len);
return request_raw(p_url, p_custom_headers, p_ssl_validate_domain, p_method, raw_data);
}
@@ -168,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;
}
@@ -184,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();
@@ -226,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;
}
@@ -245,7 +228,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
// 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;
}
@@ -290,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: {
@@ -299,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;
@@ -309,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;
@@ -324,24 +307,25 @@ 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 migh have been done
+ // Request might have been done
} else {
// Did not request yet, do request
- Error err = client->request_raw(method, request_string, headers, request_data);
+ 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;
}
@@ -364,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;
}
@@ -373,59 +357,65 @@ 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;
}
}
}
client->poll();
+ if (client->get_status() != HTTPClient::STATUS_BODY) {
+ return false;
+ }
PackedByteArray chunk = client->read_response_body_chunk();
- downloaded.add(chunk.size());
- if (file) {
- 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());
- return true;
+ if (chunk.size()) {
+ downloaded.add(chunk.size());
+ if (file) {
+ const uint8_t *r = chunk.ptr();
+ file->store_buffer(r, chunk.size());
+ if (file->get_error() != OK) {
+ call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray());
+ return true;
+ }
+ } else {
+ body.append_array(chunk);
}
- } else {
- body.append_array(chunk);
}
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;
}
return false;
} 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;
}
@@ -450,7 +440,7 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra
is_compressed = false;
}
- const PackedByteArray *data = NULL;
+ const PackedByteArray *data = nullptr;
if (accept_gzip && is_compressed && p_data.size() > 0) {
// Decompress request body
@@ -473,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) {
@@ -573,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() {
@@ -638,7 +628,7 @@ void HTTPRequest::_bind_methods() {
}
HTTPRequest::HTTPRequest() {
- client.instance();
+ client = Ref<HTTPClient>(HTTPClient::create());
timer = memnew(Timer);
timer->set_one_shot(true);
timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout));
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index 92b0ff28e9..22e822253f 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -31,8 +31,8 @@
#ifndef HTTPREQUEST_H
#define HTTPREQUEST_H
+#include "core/io/file_access.h"
#include "core/io/http_client.h"
-#include "core/os/file_access.h"
#include "core/os/thread.h"
#include "core/templates/safe_refcount.h"
#include "node.h"
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index 1661984e30..89dac5f5a8 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -88,7 +88,7 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene
if (!ps.is_valid()) {
return nullptr;
}
- Node *scene = ps->instance();
+ Node *scene = ps->instantiate();
if (!scene) {
return nullptr;
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index f6a0f5a6c0..0d060240de 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -35,6 +35,7 @@
#include "core/object/message_queue.h"
#include "core/string/print_string.h"
#include "instance_placeholder.h"
+#include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/resources/packed_scene.h"
#include "scene/scene_string_names.h"
@@ -292,7 +293,7 @@ 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, "Invalid new child position: " + itos(p_pos) + ".");
+ 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.");
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).");
@@ -402,6 +403,7 @@ void Node::set_process_mode(ProcessMode p_mode) {
}
bool prev_can_process = can_process();
+ bool prev_enabled = _is_enabled();
data.process_mode = p_mode;
@@ -416,6 +418,7 @@ void Node::set_process_mode(ProcessMode p_mode) {
}
bool next_can_process = can_process();
+ bool next_enabled = _is_enabled();
int pause_notification = 0;
@@ -425,12 +428,21 @@ void Node::set_process_mode(ProcessMode p_mode) {
pause_notification = NOTIFICATION_UNPAUSED;
}
- _propagate_process_owner(data.process_owner, pause_notification);
+ int enabled_notification = 0;
+
+ if (prev_enabled && !next_enabled) {
+ enabled_notification = NOTIFICATION_DISABLED;
+ } else if (!prev_enabled && next_enabled) {
+ enabled_notification = NOTIFICATION_ENABLED;
+ }
+
+ _propagate_process_owner(data.process_owner, pause_notification, enabled_notification);
+
#ifdef TOOLS_ENABLED
// This is required for the editor to update the visibility of disabled nodes
- // Its very expensive during runtime to change, so editor-only
+ // 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
}
@@ -454,17 +466,21 @@ Node::ProcessMode Node::get_process_mode() const {
return data.process_mode;
}
-void Node::_propagate_process_owner(Node *p_owner, int p_notification) {
+void Node::_propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification) {
data.process_owner = p_owner;
- if (p_notification != 0) {
- notification(p_notification);
+ if (p_pause_notification != 0) {
+ notification(p_pause_notification);
+ }
+
+ if (p_enabled_notification != 0) {
+ notification(p_enabled_notification);
}
for (int i = 0; i < data.children.size(); i++) {
Node *c = data.children[i];
if (c->data.process_mode == PROCESS_MODE_INHERIT) {
- c->_propagate_process_owner(p_owner, p_notification);
+ c->_propagate_process_owner(p_owner, p_pause_notification, p_enabled_notification);
}
}
}
@@ -491,36 +507,24 @@ bool Node::is_network_master() const {
/***** RPC CONFIG ********/
-uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode) {
- uint16_t mid = get_node_rpc_method_id(p_method);
- if (mid == UINT16_MAX) {
- // It's new
- NetData nd;
- nd.name = p_method;
- nd.mode = p_mode;
- data.rpc_methods.push_back(nd);
- return ((uint16_t)data.rpc_methods.size() - 1) | (1 << 15);
- } else {
- int c_mid = (~(1 << 15)) & mid;
- data.rpc_methods.write[c_mid].mode = p_mode;
- return mid;
- }
-}
-
-uint16_t Node::rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode) {
- uint16_t pid = get_node_rset_property_id(p_property);
- if (pid == UINT16_MAX) {
- // It's new
- NetData nd;
- nd.name = p_property;
- nd.mode = p_mode;
- data.rpc_properties.push_back(nd);
- return ((uint16_t)data.rpc_properties.size() - 1) | (1 << 15);
- } else {
- int c_pid = (~(1 << 15)) & pid;
- data.rpc_properties.write[c_pid].mode = p_mode;
- return pid;
+uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, MultiplayerPeer::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];
+ nd.rpc_mode = p_rpc_mode;
+ nd.transfer_mode = p_transfer_mode;
+ nd.channel = p_channel;
+ return i | (1 << 15);
+ }
}
+ // New method
+ MultiplayerAPI::RPCConfig nd;
+ nd.name = p_method;
+ nd.rpc_mode = p_rpc_mode;
+ nd.transfer_mode = p_transfer_mode;
+ nd.channel = p_channel;
+ data.rpc_methods.push_back(nd);
+ return ((uint16_t)data.rpc_methods.size() - 1) | (1 << 15);
}
/***** RPC FUNCTIONS ********/
@@ -536,7 +540,7 @@ void Node::rpc(const StringName &p_method, VARIANT_ARG_DECLARE) {
argc++;
}
- rpcp(0, false, p_method, argptr, argc);
+ rpcp(0, p_method, argptr, argc);
}
void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
@@ -550,35 +554,7 @@ void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE
argc++;
}
- rpcp(p_peer_id, false, p_method, argptr, argc);
-}
-
-void Node::rpc_unreliable(const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- rpcp(0, true, p_method, argptr, argc);
-}
-
-void Node::rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- rpcp(p_peer_id, true, p_method, argptr, argc);
+ rpcp(p_peer_id, p_method, argptr, argc);
}
Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@@ -591,13 +567,13 @@ Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallEr
if (p_args[0]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
- r_error.expected = Variant::STRING;
+ r_error.expected = Variant::STRING_NAME;
return Variant();
}
StringName method = *p_args[0];
- rpcp(0, false, method, &p_args[1], p_argcount - 1);
+ rpcp(0, method, &p_args[1], p_argcount - 1);
r_error.error = Callable::CallError::CALL_OK;
return Variant();
@@ -620,99 +596,24 @@ Variant Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::Cal
if (p_args[1]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
- r_error.expected = Variant::STRING;
+ r_error.expected = Variant::STRING_NAME;
return Variant();
}
int peer_id = *p_args[0];
StringName method = *p_args[1];
- rpcp(peer_id, false, method, &p_args[2], p_argcount - 2);
+ rpcp(peer_id, method, &p_args[2], p_argcount - 2);
r_error.error = Callable::CallError::CALL_OK;
return Variant();
}
-Variant Node::_rpc_unreliable_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- return Variant();
- }
-
- if (p_args[0]->get_type() != Variant::STRING_NAME) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- return Variant();
- }
-
- StringName method = *p_args[0];
-
- rpcp(0, true, method, &p_args[1], p_argcount - 1);
-
- r_error.error = Callable::CallError::CALL_OK;
- return Variant();
-}
-
-Variant Node::_rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 2;
- return Variant();
- }
-
- if (p_args[0]->get_type() != Variant::INT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- return Variant();
- }
-
- if (p_args[1]->get_type() != Variant::STRING_NAME) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING;
- return Variant();
- }
-
- int peer_id = *p_args[0];
- StringName method = *p_args[1];
-
- rpcp(peer_id, true, method, &p_args[2], p_argcount - 2);
-
- r_error.error = Callable::CallError::CALL_OK;
- return Variant();
-}
-
-void Node::rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) {
+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, p_unreliable, p_method, p_arg, p_argcount);
-}
-
-void Node::rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
- ERR_FAIL_COND(!is_inside_tree());
- get_multiplayer()->rsetp(this, p_peer_id, p_unreliable, p_property, p_value);
-}
-
-/******** RSET *********/
-void Node::rset(const StringName &p_property, const Variant &p_value) {
- rsetp(0, false, p_property, p_value);
-}
-
-void Node::rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value) {
- rsetp(p_peer_id, false, p_property, p_value);
-}
-
-void Node::rset_unreliable(const StringName &p_property, const Variant &p_value) {
- rsetp(0, true, p_property, p_value);
+ get_multiplayer()->rpcp(this, p_peer_id, true, p_method, p_arg, p_argcount);
}
-void Node::rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value) {
- rsetp(p_peer_id, true, p_property, p_value);
-}
-
-//////////// end of rpc
Ref<MultiplayerAPI> Node::get_multiplayer() const {
if (multiplayer.is_valid()) {
return multiplayer;
@@ -731,99 +632,11 @@ void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
multiplayer = p_multiplayer;
}
-uint16_t Node::get_node_rpc_method_id(const StringName &p_method) const {
- for (int i = 0; i < data.rpc_methods.size(); i++) {
- if (data.rpc_methods[i].name == p_method) {
- // Returns `i` with the high bit set to 1 so we know that this id comes
- // from the node and not the script.
- return i | (1 << 15);
- }
- }
- return UINT16_MAX;
-}
-
-StringName Node::get_node_rpc_method(const uint16_t p_rpc_method_id) const {
- // Make sure this is a node generated ID.
- if (((1 << 15) & p_rpc_method_id) > 0) {
- int mid = (~(1 << 15)) & p_rpc_method_id;
- if (mid < data.rpc_methods.size()) {
- return data.rpc_methods[mid].name;
- }
- }
- return StringName();
-}
-
-MultiplayerAPI::RPCMode Node::get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- // Make sure this is a node generated ID.
- if (((1 << 15) & p_rpc_method_id) > 0) {
- int mid = (~(1 << 15)) & p_rpc_method_id;
- if (mid < data.rpc_methods.size()) {
- return data.rpc_methods[mid].mode;
- }
- }
- return MultiplayerAPI::RPC_MODE_DISABLED;
-}
-
-MultiplayerAPI::RPCMode Node::get_node_rpc_mode(const StringName &p_method) const {
- return get_node_rpc_mode_by_id(get_node_rpc_method_id(p_method));
-}
-
-uint16_t Node::get_node_rset_property_id(const StringName &p_property) const {
- for (int i = 0; i < data.rpc_properties.size(); i++) {
- if (data.rpc_properties[i].name == p_property) {
- // Returns `i` with the high bit set to 1 so we know that this id comes
- // from the node and not the script.
- return i | (1 << 15);
- }
- }
- return UINT16_MAX;
-}
-
-StringName Node::get_node_rset_property(const uint16_t p_rset_property_id) const {
- // Make sure this is a node generated ID.
- if (((1 << 15) & p_rset_property_id) > 0) {
- int mid = (~(1 << 15)) & p_rset_property_id;
- if (mid < data.rpc_properties.size()) {
- return data.rpc_properties[mid].name;
- }
- }
- return StringName();
-}
-
-MultiplayerAPI::RPCMode Node::get_node_rset_mode_by_id(const uint16_t p_rset_property_id) const {
- if (((1 << 15) & p_rset_property_id) > 0) {
- int mid = (~(1 << 15)) & p_rset_property_id;
- if (mid < data.rpc_properties.size()) {
- return data.rpc_properties[mid].mode;
- }
- }
- return MultiplayerAPI::RPC_MODE_DISABLED;
-}
-
-MultiplayerAPI::RPCMode Node::get_node_rset_mode(const StringName &p_property) const {
- return get_node_rset_mode_by_id(get_node_rset_property_id(p_property));
+Vector<MultiplayerAPI::RPCConfig> Node::get_node_rpc_methods() const {
+ return data.rpc_methods;
}
-String Node::get_rpc_md5() const {
- String rpc_list;
- for (int i = 0; i < data.rpc_methods.size(); i += 1) {
- rpc_list += String(data.rpc_methods[i].name);
- }
- for (int i = 0; i < data.rpc_properties.size(); i += 1) {
- rpc_list += String(data.rpc_properties[i].name);
- }
- if (get_script_instance()) {
- Vector<ScriptNetData> rpc = get_script_instance()->get_rpc_methods();
- for (int i = 0; i < rpc.size(); i += 1) {
- rpc_list += String(rpc[i].name);
- }
- rpc = get_script_instance()->get_rset_properties();
- for (int i = 0; i < rpc.size(); i += 1) {
- rpc_list += String(rpc[i].name);
- }
- }
- return rpc_list.md5_text();
-}
+//////////// end of rpc
bool Node::can_process_notification(int p_what) const {
switch (p_what) {
@@ -871,6 +684,27 @@ bool Node::_can_process(bool p_paused) const {
}
}
+bool Node::_is_enabled() const {
+ ProcessMode process_mode;
+
+ if (data.process_mode == PROCESS_MODE_INHERIT) {
+ if (!data.process_owner) {
+ process_mode = PROCESS_MODE_PAUSABLE;
+ } else {
+ process_mode = data.process_owner->data.process_mode;
+ }
+ } else {
+ process_mode = data.process_mode;
+ }
+
+ return (process_mode != PROCESS_MODE_DISABLED);
+}
+
+bool Node::is_enabled() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
+ return _is_enabled();
+}
+
float Node::get_physics_process_delta_time() const {
if (data.tree) {
return data.tree->get_physics_process_time();
@@ -1021,22 +855,8 @@ void Node::_set_name_nocheck(const StringName &p_name) {
data.name = p_name;
}
-String Node::invalid_character = ". : @ / \"";
-
-bool Node::_validate_node_name(String &p_name) {
- String name = p_name;
- Vector<String> chars = Node::invalid_character.split(" ");
- for (int i = 0; i < chars.size(); i++) {
- name = name.replace(chars[i], "");
- }
- bool is_valid = name == p_name;
- p_name = name;
- return is_valid;
-}
-
void Node::set_name(const String &p_name) {
- String name = p_name;
- _validate_node_name(name);
+ String name = p_name.validate_node_name();
ERR_FAIL_COND(name == "");
data.name = name;
@@ -1048,7 +868,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();
}
@@ -1144,7 +964,7 @@ String increase_numeric_string(const String &s) {
void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const {
if (name == StringName()) {
- //no name and a new nade is needed, create one.
+ //no name and a new name is needed, create one.
name = p_child->get_class();
// Adjust casing according to project setting. The current type name is expected to be in PascalCase.
@@ -1170,7 +990,7 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
bool exists = false;
for (int i = 0; i < cc; i++) {
- if (children_ptr[i] == p_child) { //exclude self in renaming if its already a child
+ if (children_ptr[i] == p_child) { //exclude self in renaming if it's already a child
continue;
}
if (children_ptr[i]->data.name == name) {
@@ -1254,8 +1074,11 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
void Node::add_child(Node *p_child, bool p_legible_unique_name) {
ERR_FAIL_NULL(p_child);
- ERR_FAIL_COND_MSG(p_child == this, "Can't add child '" + p_child->get_name() + "' to itself."); // adding to itself!
- ERR_FAIL_COND_MSG(p_child->data.parent, "Can't add child '" + p_child->get_name() + "' to '" + get_name() + "', already has a parent '" + p_child->data.parent->get_name() + "'."); //Fail if node has a parent
+ 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
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(p_child->is_ancestor_of(this), vformat("Can't add child '%s' to '%s' as it would result in a cyclic dependency since '%s' is already a parent of '%s'.", p_child->get_name(), get_name(), p_child->get_name(), get_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 */
@@ -1266,7 +1089,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name) {
void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
ERR_FAIL_NULL(p_sibling);
- ERR_FAIL_COND_MSG(p_sibling == this, "Can't add sibling '" + p_sibling->get_name() + "' to itself."); // adding to itself!
+ 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);
@@ -1321,7 +1144,7 @@ void Node::remove_child(Node *p_child) {
}
}
- ERR_FAIL_COND_MSG(idx == -1, "Cannot remove child node " + p_child->get_name() + " as it is not a child of this node.");
+ 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
@@ -1442,7 +1265,15 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
Node *Node::get_node(const NodePath &p_path) const {
Node *node = get_node_or_null(p_path);
- ERR_FAIL_COND_V_MSG(!node, nullptr, "Node not found: " + p_path + ".");
+
+ if (p_path.is_absolute()) {
+ ERR_FAIL_COND_V_MSG(!node, nullptr,
+ vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, get_path()));
+ } else {
+ ERR_FAIL_COND_V_MSG(!node, nullptr,
+ vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, get_path()));
+ }
+
return node;
}
@@ -1489,7 +1320,7 @@ Node *Node::find_parent(const String &p_mask) const {
return nullptr;
}
-bool Node::is_a_parent_of(const Node *p_node) const {
+bool Node::is_ancestor_of(const Node *p_node) const {
ERR_FAIL_NULL_V(p_node, false);
Node *p = p_node->data.parent;
while (p) {
@@ -1696,7 +1527,7 @@ NodePath Node::get_path_to(const Node *p_node) const {
n = n->data.parent;
}
- path.invert();
+ path.reverse();
return NodePath(path, false);
}
@@ -1717,7 +1548,7 @@ NodePath Node::get_path() const {
n = n->data.parent;
}
- path.invert();
+ path.reverse();
data.path_cache = memnew(NodePath(path, true));
@@ -1892,6 +1723,13 @@ int Node::get_index() const {
return data.pos;
}
+Ref<Tween> Node::create_tween() {
+ ERR_FAIL_COND_V_MSG(!data.tree, nullptr, "Can't create Tween when not inside scene tree.");
+ Ref<Tween> tween = get_tree()->create_tween();
+ tween->bind_node(this);
+ return tween;
+}
+
void Node::remove_and_skip() {
ERR_FAIL_COND(!data.parent);
@@ -1947,11 +1785,11 @@ String Node::get_editor_description() const {
void Node::set_editable_instance(Node *p_node, bool p_editable) {
ERR_FAIL_NULL(p_node);
- ERR_FAIL_COND(!is_a_parent_of(p_node));
+ ERR_FAIL_COND(!is_ancestor_of(p_node));
if (!p_editable) {
p_node->data.editable_instance = false;
// Avoid this flag being needlessly saved;
- // also give more visual feedback if editable children is re-enabled
+ // also give more visual feedback if editable children are re-enabled
set_display_folded(false);
} else {
p_node->data.editable_instance = true;
@@ -1962,10 +1800,40 @@ bool Node::is_editable_instance(const Node *p_node) const {
if (!p_node) {
return false; // Easier, null is never editable. :)
}
- ERR_FAIL_COND_V(!is_a_parent_of(p_node), false);
+ ERR_FAIL_COND_V(!is_ancestor_of(p_node), false);
return p_node->data.editable_instance;
}
+Node *Node::get_deepest_editable_node(Node *p_start_node) const {
+ ERR_FAIL_NULL_V(p_start_node, nullptr);
+ ERR_FAIL_COND_V(!is_ancestor_of(p_start_node), p_start_node);
+
+ Node const *iterated_item = p_start_node;
+ Node *node = p_start_node;
+
+ while (iterated_item->get_owner() && iterated_item->get_owner() != this) {
+ if (!is_editable_instance(iterated_item->get_owner())) {
+ node = iterated_item->get_owner();
+ }
+
+ iterated_item = iterated_item->get_owner();
+ }
+
+ 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;
}
@@ -1993,7 +1861,7 @@ bool Node::get_scene_instance_load_placeholder() const {
Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const {
Node *node = nullptr;
- bool instanced = false;
+ bool instantiated = false;
if (Object::cast_to<InstancePlaceholder>(this)) {
const InstancePlaceholder *ip = Object::cast_to<const InstancePlaceholder>(this);
@@ -2010,13 +1878,13 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
ges = PackedScene::GEN_EDIT_STATE_INSTANCE;
}
#endif
- node = res->instance(ges);
+ node = res->instantiate(ges);
ERR_FAIL_COND_V(!node, nullptr);
- instanced = true;
+ instantiated = true;
} else {
- Object *obj = ClassDB::instance(get_class());
+ Object *obj = ClassDB::instantiate(get_class());
ERR_FAIL_COND_V(!obj, nullptr);
node = Object::cast_to<Node>(obj);
if (!node) {
@@ -2027,6 +1895,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
if (get_filename() != "") { //an instance
node->set_filename(get_filename());
+ node->data.editable_instance = data.editable_instance;
}
StringName script_property_name = CoreStringNames::get_singleton()->_script;
@@ -2035,23 +1904,30 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
List<const Node *> node_tree;
node_tree.push_front(this);
- if (instanced) {
- // Since nodes in the instanced hierarchy won't be duplicated explicitly, we need to make an inventory
- // of all the nodes in the tree of the instanced scene in order to transfer the values of the properties
+ if (instantiated) {
+ // Since nodes in the instantiated hierarchy won't be duplicated explicitly, we need to make an inventory
+ // of all the nodes in the tree of the instantiated scene in order to transfer the values of the properties
+
+ Vector<const Node *> instance_roots;
+ instance_roots.push_back(this);
for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
for (int i = 0; i < N->get()->get_child_count(); ++i) {
Node *descendant = N->get()->get_child(i);
- // Skip nodes not really belonging to the instanced hierarchy; they'll be processed normally later
- // but remember non-instanced nodes that are hidden below instanced ones
- if (descendant->data.owner != this) {
- if (descendant->get_parent() && descendant->get_parent() != this && descendant->get_parent()->data.owner == this && descendant->data.owner != descendant->get_parent()) {
+ // Skip nodes not really belonging to the instantiated hierarchy; they'll be processed normally later
+ // but remember non-instantiated nodes that are hidden below instantiated ones
+ if (!instance_roots.has(descendant->get_owner())) {
+ if (descendant->get_parent() && descendant->get_parent() != this && descendant->data.owner != descendant->get_parent()) {
hidden_roots.push_back(descendant);
}
continue;
}
node_tree.push_back(descendant);
+
+ if (descendant->get_filename() != "" && instance_roots.has(descendant->get_owner())) {
+ instance_roots.push_back(descendant);
+ }
}
}
}
@@ -2122,7 +1998,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
if (get_child(i)->data.parent_owned) {
continue;
}
- if (instanced && get_child(i)->data.owner == this) {
+ if (instantiated && get_child(i)->data.owner == this) {
continue; //part of instance
}
@@ -2242,79 +2118,11 @@ void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resourc
}
#endif
-void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const {
- if (get_owner() != get_parent()->get_owner()) {
- return;
- }
-
- Node *node = nullptr;
-
- if (get_filename() != "") {
- Ref<PackedScene> res = ResourceLoader::load(get_filename());
- ERR_FAIL_COND_MSG(res.is_null(), "Cannot load scene: " + get_filename());
- node = res->instance();
- ERR_FAIL_COND(!node);
- } else {
- Object *obj = ClassDB::instance(get_class());
- ERR_FAIL_COND_MSG(!obj, "Node: Could not duplicate: " + String(get_class()) + ".");
- node = Object::cast_to<Node>(obj);
- if (!node) {
- memdelete(obj);
- ERR_FAIL_MSG("Node: Could not duplicate: " + String(get_class()) + ".");
- }
- }
-
- List<PropertyInfo> plist;
-
- get_property_list(&plist);
-
- for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
- continue;
- }
- String name = E->get().name;
-
- Variant value = get(name).duplicate(true);
-
- node->set(name, value);
- }
-
- List<GroupInfo> groups;
- get_groups(&groups);
-
- for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next()) {
- node->add_to_group(E->get().name, E->get().persistent);
- }
-
- node->set_name(get_name());
- p_new_parent->add_child(node);
-
- Node *owner = get_owner();
-
- if (p_reown_map.has(owner)) {
- owner = p_reown_map[owner];
- }
-
- if (owner) {
- NodePath p = get_path_to(owner);
- if (owner != this) {
- Node *new_owner = node->get_node(p);
- if (new_owner) {
- node->set_owner(new_owner);
- }
- }
- }
-
- for (int i = 0; i < get_child_count(); i++) {
- get_child(i)->_duplicate_and_reown(node, p_reown_map);
- }
-}
-
// Duplication of signals must happen after all the node descendants have been copied,
// because re-targeting of connections from some descendant to another is not possible
// if the emitter node comes later in tree order than the receiver
void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
- if ((this != p_original) && !(p_original->is_a_parent_of(this))) {
+ if ((this != p_original) && !(p_original->is_ancestor_of(this))) {
return;
}
@@ -2364,49 +2172,6 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
}
}
-Node *Node::duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const {
- ERR_FAIL_COND_V(get_filename() != "", nullptr);
-
- Object *obj = ClassDB::instance(get_class());
- ERR_FAIL_COND_V_MSG(!obj, nullptr, "Node: Could not duplicate: " + String(get_class()) + ".");
-
- Node *node = Object::cast_to<Node>(obj);
- if (!node) {
- memdelete(obj);
- ERR_FAIL_V_MSG(nullptr, "Node: Could not duplicate: " + String(get_class()) + ".");
- }
- node->set_name(get_name());
-
- List<PropertyInfo> plist;
-
- get_property_list(&plist);
-
- for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
- continue;
- }
- String name = E->get().name;
- node->set(name, get(name));
- }
-
- List<GroupInfo> groups;
- get_groups(&groups);
-
- for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next()) {
- node->add_to_group(E->get().name, E->get().persistent);
- }
-
- for (int i = 0; i < get_child_count(); i++) {
- get_child(i)->_duplicate_and_reown(node, p_reown_map);
- }
-
- // Duplication of signals must happen after all the node descendants have been copied,
- // because re-targeting of connections from some descendant to another is not possible
- // if the emitter node comes later in tree order than the receiver
- _duplicate_signals(this, node);
- return node;
-}
-
static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) {
if (p_node->get_owner() == p_by) {
p_owned->push_back(p_node);
@@ -2482,7 +2247,7 @@ void Node::_replace_connections_target(Node *p_new_target) {
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());
- ERR_CONTINUE_MSG(!valid, "Attempt to connect signal '" + c.signal.get_object()->get_class() + "." + c.signal.get_name() + "' to nonexistent method '" + c.callable.get_object()->get_class() + "." + c.callable.get_method() + "'.");
+ ERR_CONTINUE_MSG(!valid, vformat("Attempt to connect signal '%s.%s' to nonexistent method '%s.%s'.", c.signal.get_object()->get_class(), c.signal.get_name(), c.callable.get_object()->get_class(), c.callable.get_method()));
c.signal.get_object()->connect(c.signal.get_name(), Callable(p_new_target, c.callable.get_method()), c.binds, c.flags);
}
}
@@ -2725,20 +2490,34 @@ void Node::clear_internal_tree_resource_paths() {
}
}
-String Node::get_configuration_warning() const {
+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_warning")) {
- return get_script_instance()->call("_get_configuration_warning");
+ get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warnings")) {
+ return get_script_instance()->call("_get_configuration_warnings");
}
- return String();
+ return Array();
}
-void Node::update_configuration_warning() {
+String Node::get_configuration_warnings_as_string() const {
+ TypedArray<String> warnings = get_configuration_warnings();
+ String all_warnings = String();
+ for (int i = 0; i < warnings.size(); i++) {
+ if (i > 0) {
+ all_warnings += "\n\n";
+ }
+ // 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;
+}
+
+void Node::update_configuration_warnings() {
#ifdef TOOLS_ENABLED
if (!is_inside_tree()) {
return;
}
- if (get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) {
+ if (get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_ancestor_of(this))) {
get_tree()->emit_signal(SceneStringNames::get_singleton()->node_configuration_warning_changed, this);
}
#endif
@@ -2785,7 +2564,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node_and_resource", "path"), &Node::_get_node_and_resource);
ClassDB::bind_method(D_METHOD("is_inside_tree"), &Node::is_inside_tree);
- ClassDB::bind_method(D_METHOD("is_a_parent_of", "node"), &Node::is_a_parent_of);
+ ClassDB::bind_method(D_METHOD("is_ancestor_of", "node"), &Node::is_ancestor_of);
ClassDB::bind_method(D_METHOD("is_greater_than", "node"), &Node::is_greater_than);
ClassDB::bind_method(D_METHOD("get_path"), &Node::get_path);
ClassDB::bind_method(D_METHOD("get_path_to", "node"), &Node::get_path_to);
@@ -2834,6 +2613,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_physics_processing_internal"), &Node::is_physics_processing_internal);
ClassDB::bind_method(D_METHOD("get_tree"), &Node::get_tree);
+ ClassDB::bind_method(D_METHOD("create_tween"), &Node::create_tween);
ClassDB::bind_method(D_METHOD("duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANCING | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS));
ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false));
@@ -2855,8 +2635,7 @@ void Node::_bind_methods() {
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", "mode"), &Node::rpc_config);
- ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config);
+ ClassDB::bind_method(D_METHOD("rpc_config", "method", "rpc_mode", "transfer_mode", "channel"), &Node::rpc_config, DEFVAL(MultiplayerPeer::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);
@@ -2873,23 +2652,14 @@ void Node::_bind_methods() {
mi.name = "rpc";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc", &Node::_rpc_bind, mi);
- mi.name = "rpc_unreliable";
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_unreliable", &Node::_rpc_unreliable_bind, mi);
mi.arguments.push_front(PropertyInfo(Variant::INT, "peer_id"));
mi.name = "rpc_id";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_id", &Node::_rpc_id_bind, mi);
- mi.name = "rpc_unreliable_id";
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_unreliable_id", &Node::_rpc_unreliable_id_bind, mi);
}
- ClassDB::bind_method(D_METHOD("rset", "property", "value"), &Node::rset);
- ClassDB::bind_method(D_METHOD("rset_id", "peer_id", "property", "value"), &Node::rset_id);
- ClassDB::bind_method(D_METHOD("rset_unreliable", "property", "value"), &Node::rset_unreliable);
- ClassDB::bind_method(D_METHOD("rset_unreliable_id", "peer_id", "property", "value"), &Node::rset_unreliable_id);
-
- ClassDB::bind_method(D_METHOD("update_configuration_warning"), &Node::update_configuration_warning);
+ ClassDB::bind_method(D_METHOD("update_configuration_warnings"), &Node::update_configuration_warnings);
BIND_CONSTANT(NOTIFICATION_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_EXIT_TREE);
@@ -2908,6 +2678,11 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS);
BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE);
+ BIND_CONSTANT(NOTIFICATION_DISABLED);
+ BIND_CONSTANT(NOTIFICATION_ENABLED);
+
+ BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE);
+ BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE);
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER);
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
@@ -2944,14 +2719,14 @@ void Node::_bind_methods() {
ADD_SIGNAL(MethodInfo("tree_exiting"));
ADD_SIGNAL(MethodInfo("tree_exited"));
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_name", "get_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_filename", "get_filename");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_owner", "get_owner");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "", "get_multiplayer");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "set_custom_multiplayer", "get_custom_multiplayer");
ADD_GROUP("Process", "process_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Inherit,Pausable,WhenPaused,Always,Disabled"), "set_process_mode", "get_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Inherit,Pausable,When Paused,Always,Disabled"), "set_process_mode", "get_process_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_priority"), "set_process_priority", "get_process_priority");
ADD_GROUP("Editor Description", "editor_");
@@ -2965,7 +2740,7 @@ void Node::_bind_methods() {
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(Variant::STRING, "_get_configuration_warning"));
+ BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, "String"), "_get_configuration_warnings"));
}
String Node::_get_name_num_separator() {
diff --git a/scene/main/node.h b/scene/main/node.h
index b3979993e0..20315d7a86 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -41,6 +41,9 @@
class Viewport;
class SceneState;
+class Tween;
+class PropertyTweener;
+
class Node : public Object {
GDCLASS(Node, Object);
OBJ_CATEGORY("Nodes");
@@ -80,11 +83,6 @@ private:
SceneTree::Group *group = nullptr;
};
- struct NetData {
- StringName name;
- MultiplayerAPI::RPCMode mode = MultiplayerAPI::RPCMode::RPC_MODE_DISABLED;
- };
-
struct Data {
String filename;
Ref<SceneState> instance_state;
@@ -116,8 +114,7 @@ private:
Node *process_owner = nullptr;
int network_master = 1; // Server by default.
- Vector<NetData> rpc_methods;
- Vector<NetData> rpc_properties;
+ Vector<MultiplayerAPI::RPCConfig> rpc_methods;
// Variables used to properly sort the node when processing, ignored otherwise.
// TODO: Should move all the stuff below to bits.
@@ -169,20 +166,17 @@ private:
void _propagate_after_exit_tree();
void _propagate_validate_owner();
void _print_stray_nodes();
- void _propagate_process_owner(Node *p_owner, int p_notification);
+ void _propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification);
Array _get_node_and_resource(const NodePath &p_path);
void _duplicate_signals(const Node *p_original, Node *p_copy) const;
- void _duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const;
Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = nullptr) const;
TypedArray<Node> _get_children() const;
Array _get_groups() const;
Variant _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant _rpc_unreliable_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);
- Variant _rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
friend class SceneTree;
@@ -190,12 +184,7 @@ private:
void _propagate_pause_notification(bool p_enable);
_FORCE_INLINE_ bool _can_process(bool p_paused) const;
-
-#ifdef TOOLS_ENABLED
- friend class SceneTreeEditor;
-#endif
- static String invalid_character;
- static bool _validate_node_name(String &p_name);
+ _FORCE_INLINE_ bool _is_enabled() const;
protected:
void _block() { data.blocked++; }
@@ -239,6 +228,8 @@ public:
NOTIFICATION_INTERNAL_PROCESS = 25,
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
NOTIFICATION_POST_ENTER_TREE = 27,
+ NOTIFICATION_DISABLED = 28,
+ NOTIFICATION_ENABLED = 29,
//keep these linked to node
NOTIFICATION_WM_MOUSE_ENTER = 1002,
@@ -260,6 +251,10 @@ public:
NOTIFICATION_APPLICATION_FOCUS_IN = MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN,
NOTIFICATION_APPLICATION_FOCUS_OUT = MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT,
NOTIFICATION_TEXT_SERVER_CHANGED = MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED,
+
+ // Editor specific node notifications
+ NOTIFICATION_EDITOR_PRE_SAVE = 9001,
+ NOTIFICATION_EDITOR_POST_SAVE = 9002,
};
/* NODE/TREE */
@@ -290,7 +285,7 @@ public:
_FORCE_INLINE_ bool is_inside_tree() const { return data.inside_tree; }
- bool is_a_parent_of(const Node *p_node) const;
+ bool is_ancestor_of(const Node *p_node) const;
bool is_greater_than(const Node *p_node) const;
NodePath get_path() const;
@@ -319,6 +314,8 @@ public:
void remove_and_skip();
int get_index() const;
+ Ref<Tween> create_tween();
+
void print_tree();
void print_tree_pretty();
@@ -330,6 +327,9 @@ public:
void set_editable_instance(Node *p_node, bool p_editable);
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 */
@@ -365,7 +365,6 @@ public:
bool is_processing_unhandled_key_input() const;
Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const;
- Node *duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const;
#ifdef TOOLS_ENABLED
Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const;
Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap, const Map<RES, RES> &p_resource_remap) const;
@@ -391,6 +390,7 @@ public:
ProcessMode get_process_mode() const;
bool can_process() const;
bool can_process_notification(int p_what) const;
+ bool is_enabled() const;
void request_ready();
@@ -419,9 +419,10 @@ public:
_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; }
- virtual String get_configuration_warning() const;
+ virtual TypedArray<String> get_configuration_warnings() const;
+ String get_configuration_warnings_as_string() const;
- void update_configuration_warning();
+ void update_configuration_warnings();
void set_display_folded(bool p_folded);
bool is_displayed_folded() const;
@@ -431,42 +432,17 @@ public:
int get_network_master() const;
bool is_network_master() const;
- uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode); // config a local method for RPC
- uint16_t rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode); // config a local property for RPC
+ uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, MultiplayerPeer::TransferMode p_transfer_mode, int p_channel = 0); // config a local method for RPC
+ Vector<MultiplayerAPI::RPCConfig> get_node_rpc_methods() const;
- void rpc(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
- void rpc_unreliable(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
- void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
- void rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
-
- void rset(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
- void rset_unreliable(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
- void rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
- void rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
-
- void rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
- void rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value);
+ 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
+ void rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount);
Ref<MultiplayerAPI> get_multiplayer() const;
Ref<MultiplayerAPI> get_custom_multiplayer() const;
void set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
- /// Returns the rpc method ID, otherwise UINT32_MAX
- uint16_t get_node_rpc_method_id(const StringName &p_method) const;
- StringName get_node_rpc_method(const uint16_t p_rpc_method_id) const;
- MultiplayerAPI::RPCMode get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
- MultiplayerAPI::RPCMode get_node_rpc_mode(const StringName &p_method) const;
-
- /// Returns the rpc property ID, otherwise UINT32_MAX
- uint16_t get_node_rset_property_id(const StringName &p_property) const;
- StringName get_node_rset_property(const uint16_t p_rset_property_id) const;
- MultiplayerAPI::RPCMode get_node_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
- MultiplayerAPI::RPCMode get_node_rset_mode(const StringName &p_property) const;
-
- /// Can be used to check if the rpc methods and the rset properties are the
- /// same across the peers.
- String get_rpc_md5() const;
-
Node();
~Node();
};
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 9f32c65f7b..2fe5d7aa78 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -33,14 +33,15 @@
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "core/input/input.h"
+#include "core/io/dir_access.h"
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/object/message_queue.h"
-#include "core/os/dir_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "node.h"
+#include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/resources/font.h"
#include "scene/resources/material.h"
@@ -54,6 +55,7 @@
#include "window.h"
#include <stdio.h>
+#include <stdlib.h>
void SceneTreeTimer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left);
@@ -167,8 +169,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);
}
@@ -388,6 +390,7 @@ void SceneTree::set_group(const StringName &p_group, const String &p_name, const
}
void SceneTree::initialize() {
+ ERR_FAIL_COND(!root);
initialized = true;
root->_set_tree(this);
MainLoop::initialize();
@@ -403,15 +406,17 @@ 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
+
+ process_tweens(p_time, true);
+
flush_transform_notifications();
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds");
root_lock--;
_flush_delete_queue();
@@ -431,19 +436,18 @@ 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
flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds");
root_lock--;
@@ -467,7 +471,7 @@ bool SceneTree::process(float 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) {
@@ -476,6 +480,8 @@ bool SceneTree::process(float p_time) {
E = N;
}
+ process_tweens(p_time, false);
+
flush_transform_notifications(); //additional transforms after timers update
_call_idle_callbacks();
@@ -484,7 +490,7 @@ bool SceneTree::process(float p_time) {
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,6 +516,32 @@ bool SceneTree::process(float p_time) {
return _quit;
}
+void SceneTree::process_tweens(float p_delta, bool p_physics) {
+ // This methods works similarly to how SceneTreeTimers are handled.
+ List<Ref<Tween>>::Element *L = tweens.back();
+
+ for (List<Ref<Tween>>::Element *E = tweens.front(); E;) {
+ List<Ref<Tween>>::Element *N = E->next();
+ // Don't process if paused or process mode doesn't match.
+ if ((paused && E->get()->should_pause()) || (p_physics == (E->get()->get_process_mode() == Tween::TWEEN_PROCESS_IDLE))) {
+ if (E == L) {
+ break;
+ }
+ E = N;
+ continue;
+ }
+
+ if (!E->get()->step(p_delta)) {
+ E->get()->set_valid(false);
+ tweens.erase(E);
+ }
+ if (E == L) {
+ break;
+ }
+ E = N;
+ }
+}
+
void SceneTree::finalize() {
_flush_delete_queue();
@@ -534,12 +566,7 @@ void SceneTree::finalize() {
}
void SceneTree::quit(int p_exit_code) {
- if (p_exit_code >= 0) {
- // Override the exit code if a positive argument is given (the default is `-1`).
- // This is a shorthand for calling `set_exit_code()` on the OS singleton then quitting.
- OS::get_singleton()->set_exit_code(p_exit_code);
- }
-
+ OS::get_singleton()->set_exit_code(p_exit_code);
_quit = true;
}
@@ -596,7 +623,7 @@ void SceneTree::set_quit_on_go_back(bool p_enable) {
#ifdef TOOLS_ENABLED
bool SceneTree::is_node_being_edited(const Node *p_node) const {
- return Engine::get_singleton()->is_editor_hint() && edited_scene_root && (edited_scene_root->is_a_parent_of(p_node) || edited_scene_root == p_node);
+ return Engine::get_singleton()->is_editor_hint() && edited_scene_root && (edited_scene_root->is_ancestor_of(p_node) || edited_scene_root == p_node);
}
#endif
@@ -900,8 +927,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();
}
@@ -920,8 +947,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();
}
@@ -956,6 +983,21 @@ bool SceneTree::has_group(const StringName &p_identifier) const {
return group_map.has(p_identifier);
}
+Node *SceneTree::get_first_node_in_group(const StringName &p_group) {
+ Map<StringName, Group>::Element *E = group_map.find(p_group);
+ if (!E) {
+ return nullptr; //no group
+ }
+
+ _update_group_order(E->get()); //update order just in case
+
+ if (E->get().nodes.size() == 0) {
+ return nullptr;
+ }
+
+ return E->get().nodes[0];
+}
+
void SceneTree::get_nodes_in_group(const StringName &p_group, List<Node *> *p_list) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
if (!E) {
@@ -1051,11 +1093,11 @@ Error SceneTree::change_scene(const String &p_path) {
Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) {
Node *new_scene = nullptr;
if (p_scene.is_valid()) {
- new_scene = p_scene->instance();
+ new_scene = p_scene->instantiate();
ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE);
}
- call_deferred("_change_scene", new_scene);
+ call_deferred(SNAME("_change_scene"), new_scene);
return OK;
}
@@ -1072,31 +1114,32 @@ void SceneTree::add_current_scene(Node *p_current) {
Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_always) {
Ref<SceneTreeTimer> stt;
- stt.instance();
+ stt.instantiate();
stt->set_process_always(p_process_always);
stt->set_time_left(p_delay_sec);
timers.push_back(stt);
return stt;
}
-void SceneTree::_network_peer_connected(int p_id) {
- emit_signal("network_peer_connected", p_id);
+Ref<Tween> SceneTree::create_tween() {
+ Ref<Tween> tween;
+ tween.instantiate();
+ tween->set_valid(true);
+ tweens.push_back(tween);
+ return tween;
}
-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");
-}
+Array SceneTree::get_processed_tweens() {
+ Array ret;
+ ret.resize(tweens.size());
-void SceneTree::_connection_failed() {
- emit_signal("connection_failed");
-}
+ int i = 0;
+ for (List<Ref<Tween>>::Element *E = tweens.front(); E; E = E->next()) {
+ ret[i] = E->get();
+ i++;
+ }
-void SceneTree::_server_disconnected() {
- emit_signal("server_disconnected");
+ return ret;
}
Ref<MultiplayerAPI> SceneTree::get_multiplayer() const {
@@ -1114,58 +1157,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() {
@@ -1187,10 +1180,12 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always"), &SceneTree::create_timer, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("create_tween"), &SceneTree::create_tween);
+ ClassDB::bind_method(D_METHOD("get_processed_tweens"), &SceneTree::get_processed_tweens);
ClassDB::bind_method(D_METHOD("get_node_count"), &SceneTree::get_node_count);
ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame);
- ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(EXIT_SUCCESS));
ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete);
@@ -1216,6 +1211,7 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_group", "group", "property", "value"), &SceneTree::set_group);
ClassDB::bind_method(D_METHOD("get_nodes_in_group", "group"), &SceneTree::_get_nodes_in_group);
+ ClassDB::bind_method(D_METHOD("get_first_node_in_group", "group"), &SceneTree::get_first_node_in_group);
ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene);
ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene);
@@ -1231,30 +1227,18 @@ 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", 0), "set_edited_scene_root", "get_edited_scene_root");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_current_scene", "get_current_scene");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "", "get_root");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_multiplayer", "get_multiplayer");
+ 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, "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");
ADD_SIGNAL(MethodInfo("tree_changed"));
- ADD_SIGNAL(MethodInfo("tree_process_mode_changed")); //editor only signal, but due to API hash it cant be removed in run-time
+ ADD_SIGNAL(MethodInfo("tree_process_mode_changed")); //editor only signal, but due to API hash it can't be removed in run-time
ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
@@ -1264,11 +1248,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);
@@ -1334,6 +1313,10 @@ SceneTree::SceneTree() {
collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000);
ProjectSettings::get_singleton()->set_custom_property_info("debug/shapes/collision/max_contacts_displayed", PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1")); // No negative
+ GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
+
+ Math::randomize();
+
// Create with mainloop.
root = memnew(Window);
@@ -1361,6 +1344,9 @@ SceneTree::SceneTree() {
const bool use_debanding = GLOBAL_DEF("rendering/anti_aliasing/quality/use_debanding", false);
root->set_use_debanding(use_debanding);
+ const bool use_occlusion_culling = GLOBAL_DEF("rendering/occlusion_culling/use_occlusion_culling", false);
+ root->set_use_occlusion_culling(use_occlusion_culling);
+
float lod_threshold = GLOBAL_DEF("rendering/mesh_lod/lod_change/threshold_pixels", 1.0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/mesh_lod/lod_change/threshold_pixels", PropertyInfo(Variant::FLOAT, "rendering/mesh_lod/lod_change/threshold_pixels", PROPERTY_HINT_RANGE, "0,1024,0.1"));
root->set_lod_threshold(lod_threshold);
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index f39780831f..0be0e185a5 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -47,9 +47,10 @@ class Window;
class Material;
class Mesh;
class SceneDebugger;
+class Tween;
-class SceneTreeTimer : public Reference {
- GDCLASS(SceneTreeTimer, Reference);
+class SceneTreeTimer : public RefCounted {
+ GDCLASS(SceneTreeTimer, RefCounted);
float time_left = 0.0;
bool process_always = true;
@@ -151,19 +152,13 @@ private:
//void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2);
List<Ref<SceneTreeTimer>> timers;
+ List<Ref<Tween>> tweens;
///network///
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;
@@ -171,6 +166,7 @@ private:
void node_added(Node *p_node);
void node_removed(Node *p_node);
void node_renamed(Node *p_node);
+ void process_tweens(float p_delta, bool p_physics_frame);
Group *add_to_group(const StringName &p_group, Node *p_node);
void remove_from_group(const StringName &p_group, Node *p_node);
@@ -245,7 +241,7 @@ public:
void set_auto_accept_quit(bool p_enable);
void set_quit_on_go_back(bool p_enable);
- void quit(int p_exit_code = -1);
+ 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; }
@@ -302,6 +298,7 @@ public:
void queue_delete(Object *p_object);
void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list);
+ Node *get_first_node_in_group(const StringName &p_group);
bool has_group(const StringName &p_identifier) const;
//void change_scene(const String& p_path);
@@ -317,6 +314,8 @@ public:
Error reload_current_scene();
Ref<SceneTreeTimer> create_timer(float p_delay_sec, bool p_process_always = true);
+ Ref<Tween> create_tween();
+ Array get_processed_tweens();
//used by Main::start, don't use otherwise
void add_current_scene(Node *p_current);
@@ -331,16 +330,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 b6b2982155..d22a6b2875 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -63,7 +63,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;
@@ -169,7 +174,7 @@ void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const
pinfo.type = Variant::TRANSFORM2D;
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
- pinfo.type = Variant::TRANSFORM;
+ pinfo.type = Variant::TRANSFORM3D;
} break;
case RS::GLOBAL_VAR_TYPE_MAT4: {
pinfo.type = Variant::PACKED_INT32_ARRAY;
@@ -228,11 +233,16 @@ 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);
+ }
}
}
- update_configuration_warning(); //may have activated
+ update_configuration_warnings(); //may have activated
}
}
@@ -260,17 +270,14 @@ void ShaderGlobalsOverride::_notification(int p_what) {
}
}
-String ShaderGlobalsOverride::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> ShaderGlobalsOverride::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!active) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene.");
+ warnings.push_back(TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."));
}
- return warning;
+ return warnings;
}
void ShaderGlobalsOverride::_bind_methods() {
diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h
index 8d8794d465..2d9c3c76bd 100644
--- a/scene/main/shader_globals_override.h
+++ b/scene/main/shader_globals_override.h
@@ -58,7 +58,7 @@ protected:
static void _bind_methods();
public:
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
ShaderGlobalsOverride();
};
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index 4bc159f6aa..ef8245076f 100644
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
@@ -37,7 +37,7 @@ void Timer::_notification(int p_what) {
case NOTIFICATION_READY: {
if (autostart) {
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) {
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_ancestor_of(this))) {
break;
}
#endif
@@ -58,7 +58,7 @@ void Timer::_notification(int p_what) {
stop();
}
- emit_signal("timeout");
+ emit_signal(SNAME("timeout"));
}
} break;
@@ -74,7 +74,7 @@ void Timer::_notification(int p_what) {
} else {
stop();
}
- emit_signal("timeout");
+ emit_signal(SNAME("timeout"));
}
} break;
@@ -207,11 +207,11 @@ void Timer::_bind_methods() {
ADD_SIGNAL(MethodInfo("timeout"));
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_callback", "get_timer_process_callback");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.001,4096,0.001,or_greater"), "set_wait_time", "get_wait_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time", PROPERTY_HINT_RANGE, "0.001,4096,0.001,or_greater,exp"), "set_wait_time", "get_wait_time");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused", PROPERTY_HINT_NONE, "", 0), "set_paused", "is_paused");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_left", PROPERTY_HINT_NONE, "", 0), "", "get_time_left");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_paused", "is_paused");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_left", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_time_left");
BIND_ENUM_CONSTANT(TIMER_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 54b670df6c..f81b512b0c 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -37,6 +37,7 @@
#include "core/os/os.h"
#include "core/string/translation.h"
+#include "scene/2d/camera_2d.h"
#include "scene/2d/collision_object_2d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/collision_object_3d.h"
@@ -131,7 +132,7 @@ bool ViewportTexture::has_alpha() const {
return false;
}
-Ref<Image> ViewportTexture::get_data() const {
+Ref<Image> ViewportTexture::get_image() const {
ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it.");
return RS::get_singleton()->texture_2d_get(vp->texture_rid);
}
@@ -183,22 +184,9 @@ public:
/////////////////////////////////////
-void Viewport::update_worlds() {
- if (!is_inside_tree()) {
- return;
- }
-
- Rect2 abstracted_rect = Rect2(Vector2(), get_visible_rect().size);
- Rect2 xformed_rect = (global_canvas_transform * canvas_transform).affine_inverse().xform(abstracted_rect);
- find_world_2d()->_update_viewport(this, xformed_rect);
- find_world_2d()->_update();
-
- find_world_3d()->_update(get_tree()->get_frame());
-}
-
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) {
- Transform object_transform = p_object->get_global_transform();
- Transform camera_transform = p_camera->get_global_transform();
+ 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
@@ -208,7 +196,7 @@ void Viewport::_collision_object_input_event(CollisionObject3D *p_object, Camera
return; //discarded
}
}
- p_object->_input_event(camera, p_input_event, p_pos, p_normal, p_shape);
+ p_object->_input_event(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;
@@ -261,16 +249,16 @@ 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("panel_window"));
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");
+ 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->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);
@@ -278,8 +266,8 @@ void Viewport::_sub_window_update(Window *p_window) {
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);
}
@@ -441,8 +429,6 @@ void Viewport::_notification(int p_what) {
_update_listener();
_update_listener_2d();
- find_world_2d()->_register_viewport(this, Rect2());
-
add_to_group("_viewports");
if (get_tree()->is_debugging_collisions_hint()) {
//2D
@@ -459,6 +445,7 @@ 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);
+ set_physics_process_internal(true);
}
} break;
@@ -477,7 +464,7 @@ void Viewport::_notification(int p_what) {
}
}
- if (cameras.size() && !camera) {
+ if (cameras.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()) {
@@ -492,16 +479,9 @@ void Viewport::_notification(int p_what) {
}
#endif
- // Enable processing for tooltips, collision debugging, physics object picking, etc.
- set_process_internal(true);
- set_physics_process_internal(true);
-
} break;
case NOTIFICATION_EXIT_TREE: {
_gui_cancel_tooltip();
- if (world_2d.is_valid()) {
- world_2d->_remove_viewport(this);
- }
RenderingServer::get_singleton()->viewport_set_scenario(viewport, RID());
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
@@ -518,6 +498,7 @@ 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());
@@ -528,6 +509,7 @@ void Viewport::_notification(int p_what) {
gui.tooltip_timer -= get_process_delta_time();
if (gui.tooltip_timer < 0) {
_gui_show_tooltip();
+ set_process_internal(false);
}
}
@@ -553,7 +535,7 @@ void Viewport::_notification(int p_what) {
RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
for (int i = 0; i < point_count; i++) {
- Transform point_transform;
+ Transform3D point_transform;
point_transform.origin = points[i];
RS::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh, i, point_transform);
}
@@ -612,15 +594,15 @@ void Viewport::_process_picking() {
if (!has_mouse_event) {
Ref<InputEventMouseMotion> mm;
- mm.instance();
+ mm.instantiate();
mm->set_device(InputEvent::DEVICE_ID_INTERNAL);
mm->set_global_position(physics_last_mousepos);
mm->set_position(physics_last_mousepos);
- mm->set_alt(physics_last_mouse_state.alt);
- mm->set_shift(physics_last_mouse_state.shift);
- mm->set_control(physics_last_mouse_state.control);
- mm->set_metakey(physics_last_mouse_state.meta);
+ mm->set_alt_pressed(physics_last_mouse_state.alt);
+ mm->set_shift_pressed(physics_last_mouse_state.shift);
+ mm->set_ctrl_pressed(physics_last_mouse_state.control);
+ mm->set_meta_pressed(physics_last_mouse_state.meta);
mm->set_button_mask(physics_last_mouse_state.mouse_mask);
physics_picking_events.push_back(mm);
}
@@ -641,10 +623,10 @@ void Viewport::_process_picking() {
physics_has_last_mousepos = true;
physics_last_mousepos = pos;
- physics_last_mouse_state.alt = mm->get_alt();
- physics_last_mouse_state.shift = mm->get_shift();
- physics_last_mouse_state.control = mm->get_control();
- physics_last_mouse_state.meta = mm->get_metakey();
+ physics_last_mouse_state.alt = mm->is_alt_pressed();
+ physics_last_mouse_state.shift = mm->is_shift_pressed();
+ physics_last_mouse_state.control = mm->is_ctrl_pressed();
+ physics_last_mouse_state.meta = mm->is_meta_pressed();
physics_last_mouse_state.mouse_mask = mm->get_button_mask();
}
@@ -656,15 +638,15 @@ void Viewport::_process_picking() {
physics_has_last_mousepos = true;
physics_last_mousepos = pos;
- physics_last_mouse_state.alt = mb->get_alt();
- physics_last_mouse_state.shift = mb->get_shift();
- physics_last_mouse_state.control = mb->get_control();
- physics_last_mouse_state.meta = mb->get_metakey();
+ physics_last_mouse_state.alt = mb->is_alt_pressed();
+ physics_last_mouse_state.shift = mb->is_shift_pressed();
+ physics_last_mouse_state.control = mb->is_ctrl_pressed();
+ physics_last_mouse_state.meta = mb->is_meta_pressed();
if (mb->is_pressed()) {
- physics_last_mouse_state.mouse_mask |= (1 << (mb->get_button_index() - 1));
+ physics_last_mouse_state.mouse_mask |= (MouseButton)(1 << (mb->get_button_index() - 1));
} else {
- physics_last_mouse_state.mouse_mask &= ~(1 << (mb->get_button_index() - 1));
+ physics_last_mouse_state.mouse_mask &= (MouseButton) ~(1 << (mb->get_button_index() - 1));
// If touch mouse raised, assume we don't know last mouse pos until new events come
if (mb->get_device() == InputEvent::DEVICE_ID_TOUCH_MOUSE) {
@@ -676,10 +658,10 @@ void Viewport::_process_picking() {
Ref<InputEventKey> k = ev;
if (k.is_valid()) {
//only for mask
- physics_last_mouse_state.alt = k->get_alt();
- physics_last_mouse_state.shift = k->get_shift();
- physics_last_mouse_state.control = k->get_control();
- physics_last_mouse_state.meta = k->get_metakey();
+ 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();
+ physics_last_mouse_state.meta = k->is_meta_pressed();
continue;
}
@@ -724,7 +706,6 @@ 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();
@@ -735,6 +716,13 @@ void Viewport::_process_picking() {
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) {
@@ -746,25 +734,7 @@ 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);
}
}
@@ -773,8 +743,8 @@ void Viewport::_process_picking() {
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_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();
@@ -791,16 +761,16 @@ void Viewport::_process_picking() {
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);
+ _collision_object_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) {
@@ -808,8 +778,8 @@ void Viewport::_process_picking() {
ObjectID new_collider;
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);
+ if (co) {
+ _collision_object_input_event(co, camera_3d, ev, result.position, result.normal, result.shape);
last_object = co;
last_id = result.collider_id;
new_collider = last_id;
@@ -877,7 +847,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 {
@@ -947,6 +917,15 @@ 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;
+}
+
void Viewport::enable_canvas_transform_override(bool p_enable) {
if (override_canvas_transform == p_enable) {
return;
@@ -1054,64 +1033,68 @@ void Viewport::_listener_make_next_current(Listener3D *p_exclude) {
}
} else {
// Attempt to reset listener to the camera position
- if (camera != nullptr) {
+ if (camera_3d != nullptr) {
_update_listener();
- _camera_transform_changed_notify();
+ _camera_3d_transform_changed_notify();
}
}
}
#endif
-void Viewport::_camera_transform_changed_notify() {
+void Viewport::_camera_3d_transform_changed_notify() {
#ifndef _3D_DISABLED
#endif
}
-void Viewport::_camera_set(Camera3D *p_camera) {
+void Viewport::_camera_3d_set(Camera3D *p_camera) {
#ifndef _3D_DISABLED
- if (camera == p_camera) {
+ if (camera_3d == p_camera) {
return;
}
- if (camera) {
- camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
+ if (camera_3d) {
+ camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
}
- camera = p_camera;
+ camera_3d = p_camera;
if (!camera_override) {
- if (camera) {
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
+ 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) {
- camera->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
+ if (camera_3d) {
+ camera_3d->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
}
_update_listener();
- _camera_transform_changed_notify();
+ _camera_3d_transform_changed_notify();
#endif
}
-bool Viewport::_camera_add(Camera3D *p_camera) {
+void Viewport::_camera_2d_set(Camera2D *p_camera_2d) {
+ camera_2d = p_camera_2d;
+}
+
+bool Viewport::_camera_3d_add(Camera3D *p_camera) {
cameras.insert(p_camera);
return cameras.size() == 1;
}
-void Viewport::_camera_remove(Camera3D *p_camera) {
+void Viewport::_camera_3d_remove(Camera3D *p_camera) {
cameras.erase(p_camera);
- if (camera == p_camera) {
- camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
- camera = nullptr;
+ if (camera_3d == p_camera) {
+ camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
+ camera_3d = nullptr;
}
}
#ifndef _3D_DISABLED
-void Viewport::_camera_make_next_current(Camera3D *p_exclude) {
+void Viewport::_camera_3d_make_next_current(Camera3D *p_exclude) {
for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
if (p_exclude == E->get()) {
continue;
@@ -1119,7 +1102,7 @@ void Viewport::_camera_make_next_current(Camera3D *p_exclude) {
if (!E->get()->is_inside_tree()) {
continue;
}
- if (camera != nullptr) {
+ if (camera_3d != nullptr) {
return;
}
@@ -1156,14 +1139,13 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
}
if (is_inside_tree()) {
- find_world_2d()->_remove_viewport(this);
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
}
if (p_world_2d.is_valid()) {
world_2d = p_world_2d;
} else {
- WARN_PRINT("Invalid world_3d");
+ WARN_PRINT("Invalid world_2d");
world_2d = Ref<World2D>(memnew(World2D));
}
@@ -1172,7 +1154,6 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
if (is_inside_tree()) {
current_canvas = find_world_2d()->get_canvas();
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
- find_world_2d()->_register_viewport(this, Rect2());
}
}
@@ -1310,8 +1291,12 @@ Listener3D *Viewport::get_listener() const {
return listener;
}
-Camera3D *Viewport::get_camera() const {
- return camera;
+Camera3D *Viewport::get_camera_3d() const {
+ return camera_3d;
+}
+
+Camera2D *Viewport::get_camera_2d() const {
+ return camera_2d;
}
void Viewport::enable_camera_override(bool p_enable) {
@@ -1329,8 +1314,8 @@ void Viewport::enable_camera_override(bool p_enable) {
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 if (camera_3d) {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera());
} else {
RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
}
@@ -1341,19 +1326,19 @@ bool Viewport::is_camera_override_enabled() const {
return camera_override;
}
-void Viewport::set_camera_override_transform(const Transform &p_transform) {
+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);
}
}
-Transform Viewport::get_camera_override_transform() const {
+Transform3D Viewport::get_camera_override_transform() const {
if (camera_override) {
return camera_override.transform;
}
- return Transform();
+ return Transform3D();
}
void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
@@ -1412,6 +1397,16 @@ 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;
}
@@ -1495,6 +1490,7 @@ void Viewport::_gui_sort_roots() {
void Viewport::_gui_cancel_tooltip() {
gui.tooltip_control = nullptr;
gui.tooltip_timer = -1;
+ set_process_internal(false);
if (gui.tooltip_popup) {
gui.tooltip_popup->queue_delete();
gui.tooltip_popup = nullptr;
@@ -1563,6 +1559,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);
@@ -1572,11 +1571,11 @@ void Viewport::_gui_show_tooltip() {
gui.tooltip_label = memnew(TooltipLabel);
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);
@@ -1621,10 +1620,10 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
Ref<InputEventMouseButton> mb = p_input;
bool cant_stop_me_now = (mb.is_valid() &&
- (mb->get_button_index() == BUTTON_WHEEL_DOWN ||
- mb->get_button_index() == BUTTON_WHEEL_UP ||
- mb->get_button_index() == BUTTON_WHEEL_LEFT ||
- mb->get_button_index() == BUTTON_WHEEL_RIGHT));
+ (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN ||
+ mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP ||
+ mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT ||
+ mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT));
Ref<InputEventPanGesture> pn = p_input;
cant_stop_me_now = pn.is_valid() || cant_stop_me_now;
@@ -1711,7 +1710,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) {
//_unblock();
}
-Control *Viewport::_gui_find_control(const Point2 &p_global) {
+Control *Viewport::gui_find_control(const Point2 &p_global) {
//aca va subwindows
_gui_sort_roots();
@@ -1756,7 +1755,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
Control *c = Object::cast_to<Control>(p_node);
- if (!c || !c->clips_input() || c->has_point(matrix.affine_inverse().xform(p_global))) {
+ if (!c || !c->is_clipping_contents() || c->has_point(matrix.affine_inverse().xform(p_global))) {
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
CanvasItem *ci = Object::cast_to<CanvasItem>(p_node->get_child(i));
if (!ci || ci->is_set_as_top_level()) {
@@ -1770,19 +1769,22 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
}
}
- if (!c) {
+ if (!c || c->data.mouse_filter == Control::MOUSE_FILTER_IGNORE) {
return nullptr;
}
matrix.affine_invert();
+ if (!c->has_point(matrix.xform(p_global))) {
+ return nullptr;
+ }
- //conditions for considering this as a valid control for return
- if (c->data.mouse_filter != Control::MOUSE_FILTER_IGNORE && c->has_point(matrix.xform(p_global)) && (!gui.drag_preview || (c != gui.drag_preview && !gui.drag_preview->is_a_parent_of(c)))) {
+ Control *drag_preview = _gui_get_drag_preview();
+ if (!drag_preview || (c != drag_preview && !drag_preview->is_ancestor_of(c))) {
r_inv_xform = matrix;
return c;
- } else {
- return nullptr;
}
+
+ return nullptr;
}
bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check) {
@@ -1827,6 +1829,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = nullptr;
Point2 mpos = mb->get_position();
+ gui.last_mouse_pos = mpos;
if (mb->is_pressed()) {
Size2 pos = mpos;
if (gui.mouse_focus_mask) {
@@ -1847,7 +1850,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
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) {
@@ -1857,7 +1860,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1);
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
gui.drag_accum = Vector2();
gui.drag_attempted = false;
}
@@ -1880,7 +1883,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
#endif
- if (mb->get_button_index() == 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);
@@ -1911,7 +1914,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() == BUTTON_LEFT) {
+ 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
if (gui.mouse_focus) {
_gui_drop(gui.mouse_focus, pos, false);
@@ -1920,9 +1923,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_data = Variant();
gui.dragging = false;
- if (gui.drag_preview) {
- memdelete(gui.drag_preview);
- gui.drag_preview = nullptr;
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
+ memdelete(drag_preview);
+ gui.drag_preview_id = ObjectID();
}
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
//change mouse accordingly
@@ -1930,14 +1934,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
_gui_cancel_tooltip();
} else {
- if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
+ if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (gui.drag_mouse_over) {
_gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false);
}
- if (gui.drag_preview && mb->get_button_index() == BUTTON_LEFT) {
- memdelete(gui.drag_preview);
- gui.drag_preview = nullptr;
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
+ memdelete(drag_preview);
+ gui.drag_preview_id = ObjectID();
}
gui.drag_data = Variant();
@@ -1973,7 +1978,7 @@ 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()==BUTTON_LEFT) {
+ /*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
}*/
@@ -1986,7 +1991,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) {
@@ -2017,7 +2022,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = nullptr;
// D&D
- if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ 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) {
@@ -2034,10 +2039,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.mouse_focus_mask = 0;
break;
} else {
- if (gui.drag_preview != nullptr) {
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
ERR_PRINT("Don't set a drag preview and return null data. Preview was deleted and drag request ignored.");
- memdelete(gui.drag_preview);
- gui.drag_preview = nullptr;
+ memdelete(drag_preview);
+ gui.drag_preview_id = ObjectID();
}
gui.dragging = false;
}
@@ -2068,7 +2074,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) {
@@ -2136,6 +2142,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.tooltip_control = over;
gui.tooltip_pos = over->get_screen_transform().xform(pos);
gui.tooltip_timer = gui.tooltip_delay;
+ set_process_internal(true);
}
}
@@ -2177,8 +2184,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_data.get_type() != Variant::NIL) {
//handle dragandrop
- if (gui.drag_preview) {
- gui.drag_preview->set_position(mpos);
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
+ drag_preview->set_position(mpos);
}
gui.drag_mouse_over = over;
@@ -2194,7 +2202,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
embedder = this;
viewport_pos = mpos;
} else {
- //not an embeder, 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()) {
@@ -2216,7 +2224,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
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;
}
@@ -2254,12 +2262,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
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);
+ 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);
- if (mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
bool can_drop = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, true);
if (!can_drop) {
@@ -2282,7 +2290,7 @@ 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
@@ -2317,7 +2325,7 @@ 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
@@ -2338,7 +2346,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()) {
@@ -2384,37 +2392,35 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *from = gui.key_focus ? gui.key_focus : nullptr; //hmm
//keyboard focus
- //if (from && p_event->is_pressed() && !p_event->get_alt() && !p_event->get_metakey() && !p_event->key->get_command()) {
+ //if (from && p_event->is_pressed() && !p_event->is_alt_pressed() && !p_event->is_meta_pressed() && !p_event->key->is_command_pressed()) {
Ref<InputEventKey> k = p_event;
- //need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/righ/etc> is handled here when it shouldn't be.
- bool mods = k.is_valid() && (k->get_control() || k->get_alt() || k->get_shift() || k->get_metakey());
+ //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()) {
Control *next = nullptr;
- Input *input = Input::get_singleton();
-
- if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) {
+ if (p_event->is_action_pressed("ui_focus_next", true)) {
next = from->find_next_valid_focus();
}
- if (p_event->is_action_pressed("ui_focus_prev") && input->is_action_just_pressed("ui_focus_prev")) {
+ if (p_event->is_action_pressed("ui_focus_prev", true)) {
next = from->find_prev_valid_focus();
}
- if (!mods && p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) {
+ if (!mods && p_event->is_action_pressed("ui_up", true)) {
next = from->_get_focus_neighbor(SIDE_TOP);
}
- if (!mods && p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) {
+ if (!mods && p_event->is_action_pressed("ui_left", true)) {
next = from->_get_focus_neighbor(SIDE_LEFT);
}
- if (!mods && p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) {
+ if (!mods && p_event->is_action_pressed("ui_right", true)) {
next = from->_get_focus_neighbor(SIDE_RIGHT);
}
- if (!mods && p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) {
+ if (!mods && p_event->is_action_pressed("ui_down", true)) {
next = from->_get_focus_neighbor(SIDE_BOTTOM);
}
@@ -2453,15 +2459,29 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
ERR_FAIL_COND(p_control->is_inside_tree());
ERR_FAIL_COND(p_control->get_parent() != nullptr);
- if (gui.drag_preview) {
- memdelete(gui.drag_preview);
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
+ memdelete(drag_preview);
}
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_control->raise();
- gui.drag_preview = p_control;
+ gui.drag_preview_id = p_control->get_instance_id();
+}
+
+Control *Viewport::_gui_get_drag_preview() {
+ if (gui.drag_preview_id.is_null()) {
+ return nullptr;
+ } else {
+ Control *drag_preview = Object::cast_to<Control>(ObjectDB::get_instance(gui.drag_preview_id));
+ if (!drag_preview) {
+ ERR_PRINT("Don't free the control set as drag preview.");
+ gui.drag_preview_id = ObjectID();
+ }
+ return drag_preview;
+ }
}
void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) {
@@ -2517,6 +2537,8 @@ void Viewport::_gui_remove_control(Control *p_control) {
}
Window *Viewport::get_base_window() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
+
Viewport *v = const_cast<Viewport *>(this);
Window *w = Object::cast_to<Window>(v);
while (!w) {
@@ -2551,7 +2573,7 @@ void Viewport::_gui_control_grab_focus(Control *p_control) {
}
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();
}
@@ -2573,10 +2595,10 @@ void Viewport::_drop_mouse_focus() {
for (int i = 0; i < 3; i++) {
if (mask & (1 << i)) {
Ref<InputEventMouseButton> mb;
- mb.instance();
+ mb.instantiate();
mb->set_position(c->get_local_mouse_position());
mb->set_global_position(c->get_local_mouse_position());
- mb->set_button_index(i + 1);
+ mb->set_button_index(MouseButton(i + 1));
mb->set_pressed(false);
c->call(SceneStringNames::get_singleton()->_gui_input, mb);
}
@@ -2586,20 +2608,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
+}
+
+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()) {
@@ -2607,18 +2650,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() {
@@ -2627,7 +2683,7 @@ 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() {
@@ -2649,12 +2705,12 @@ void Viewport::_post_gui_grab_click_focus() {
for (int i = 0; i < 3; i++) {
if (mask & (1 << i)) {
Ref<InputEventMouseButton> mb;
- mb.instance();
+ mb.instantiate();
- //send unclic
+ //send unclick
mb->set_position(click);
- mb->set_button_index(i + 1);
+ mb->set_button_index(MouseButton(i + 1));
mb->set_pressed(false);
gui.mouse_focus->call(SceneStringNames::get_singleton()->_gui_input, mb);
}
@@ -2667,12 +2723,12 @@ void Viewport::_post_gui_grab_click_focus() {
for (int i = 0; i < 3; i++) {
if (mask & (1 << i)) {
Ref<InputEventMouseButton> mb;
- mb.instance();
+ mb.instantiate();
- //send clic
+ //send click
mb->set_position(click);
- mb->set_button_index(i + 1);
+ mb->set_button_index(MouseButton(i + 1));
mb->set_pressed(true);
gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb);
}
@@ -2700,7 +2756,7 @@ 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;
@@ -2712,7 +2768,7 @@ Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subw
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;
@@ -2762,7 +2818,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_V(gui.subwindow_focused == nullptr, false);
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ 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
@@ -2794,7 +2850,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;
@@ -2887,7 +2943,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
//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() == BUTTON_LEFT) {
+ 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];
@@ -2898,7 +2954,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
if (!sw.window->get_flag(Window::FLAG_BORDERLESS)) {
//check top bar
- int title_height = sw.window->get_theme_constant("title_height");
+ 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;
@@ -2906,9 +2962,9 @@ 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);
@@ -3011,7 +3067,7 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
return;
}
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this)) {
return;
}
@@ -3046,13 +3102,14 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
}
void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
+ ERR_FAIL_COND(p_event.is_null());
ERR_FAIL_COND(!is_inside_tree());
if (disable_input || !_can_consume_input_events()) {
return;
}
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this)) {
return;
}
@@ -3125,8 +3182,13 @@ bool Viewport::is_using_own_world_3d() const {
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");
+ }
}
}
@@ -3155,20 +3217,17 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data;
}
-String Viewport::get_configuration_warning() 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.");
}*/
- String warning = Node::get_configuration_warning();
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (size.x == 0 || size.y == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Viewport size must be greater than 0 to render anything.");
+ warnings.push_back(TTR("Viewport size must be greater than 0 to render anything."));
}
- return warning;
+ return warnings;
}
void Viewport::gui_reset_canvas_sort_index() {
@@ -3206,8 +3265,9 @@ Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
}
void Viewport::set_use_debanding(bool p_use_debanding) {
- if (use_debanding == p_use_debanding)
+ if (use_debanding == p_use_debanding) {
return;
+ }
use_debanding = p_use_debanding;
RS::get_singleton()->viewport_set_use_debanding(viewport, p_use_debanding);
}
@@ -3224,6 +3284,21 @@ float Viewport::get_lod_threshold() const {
return lod_threshold;
}
+void Viewport::set_use_occlusion_culling(bool p_use_occlusion_culling) {
+ if (use_occlusion_culling == p_use_occlusion_culling) {
+ return;
+ }
+
+ use_occlusion_culling = p_use_occlusion_culling;
+ RS::get_singleton()->viewport_set_use_occlusion_culling(viewport, p_use_occlusion_culling);
+
+ notify_property_list_changed();
+}
+
+bool Viewport::is_using_occlusion_culling() const {
+ return use_occlusion_culling;
+}
+
void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
debug_draw = p_debug_draw;
RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
@@ -3233,8 +3308,8 @@ Viewport::DebugDraw Viewport::get_debug_draw() const {
return debug_draw;
}
-int Viewport::get_render_info(RenderInfo p_info) {
- return RS::get_singleton()->viewport_get_render_info(viewport, RS::ViewportRenderInfo(p_info));
+int Viewport::get_render_info(RenderInfoType p_type, RenderInfo p_info) {
+ return RS::get_singleton()->viewport_get_render_info(viewport, RS::ViewportRenderInfoType(p_type), RS::ViewportRenderInfo(p_info));
}
void Viewport::set_snap_controls_to_pixels(bool p_enable) {
@@ -3292,6 +3367,7 @@ bool Viewport::is_input_handled() const {
return local_input_handled;
} else {
const Viewport *vp = this;
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
while (true) {
if (Object::cast_to<Window>(vp)) {
break;
@@ -3313,9 +3389,6 @@ bool Viewport::is_handling_input_locally() const {
return handle_input_locally;
}
-void Viewport::_validate_property(PropertyInfo &property) const {
-}
-
void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter) {
ERR_FAIL_INDEX(p_filter, DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX);
@@ -3460,10 +3533,16 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_debanding", "enable"), &Viewport::set_use_debanding);
ClassDB::bind_method(D_METHOD("is_using_debanding"), &Viewport::is_using_debanding);
+ ClassDB::bind_method(D_METHOD("set_use_occlusion_culling", "enable"), &Viewport::set_use_occlusion_culling);
+ ClassDB::bind_method(D_METHOD("is_using_occlusion_culling"), &Viewport::is_using_occlusion_culling);
+
ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw);
ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw);
- ClassDB::bind_method(D_METHOD("get_render_info", "info"), &Viewport::get_render_info);
+ 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);
@@ -3475,12 +3554,11 @@ void Viewport::_bind_methods() {
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("update_worlds"), &Viewport::update_worlds);
-
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("get_camera_3d"), &Viewport::get_camera_3d);
+ ClassDB::bind_method(D_METHOD("get_camera_2d"), &Viewport::get_camera_2d);
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);
@@ -3488,6 +3566,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
+ ClassDB::bind_method(D_METHOD("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);
@@ -3545,21 +3626,24 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr");
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");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
+ 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::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa");
+ 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, "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");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_lod_threshold", "get_lod_threshold");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
ADD_GROUP("Canvas Items", "canvas_item_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
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");
@@ -3580,8 +3664,8 @@ void Viewport::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_1", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 1);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_2", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 2);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_3", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 3);
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_canvas_transform", "get_canvas_transform");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_global_canvas_transform", "get_global_canvas_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "canvas_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_canvas_transform", "get_canvas_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_canvas_transform", "get_global_canvas_transform");
ADD_SIGNAL(MethodInfo("size_changed"));
ADD_SIGNAL(MethodInfo("gui_focus_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
@@ -3607,22 +3691,23 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_MAX);
BIND_ENUM_CONSTANT(RENDER_INFO_OBJECTS_IN_FRAME);
- BIND_ENUM_CONSTANT(RENDER_INFO_VERTICES_IN_FRAME);
- BIND_ENUM_CONSTANT(RENDER_INFO_MATERIAL_CHANGES_IN_FRAME);
- BIND_ENUM_CONSTANT(RENDER_INFO_SHADER_CHANGES_IN_FRAME);
- BIND_ENUM_CONSTANT(RENDER_INFO_SURFACE_CHANGES_IN_FRAME);
+ BIND_ENUM_CONSTANT(RENDER_INFO_PRIMITIVES_IN_FRAME);
BIND_ENUM_CONSTANT(RENDER_INFO_DRAW_CALLS_IN_FRAME);
BIND_ENUM_CONSTANT(RENDER_INFO_MAX);
+ BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_VISIBLE);
+ BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_SHADOW);
+ BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_MAX);
+
BIND_ENUM_CONSTANT(DEBUG_DRAW_DISABLED);
BIND_ENUM_CONSTANT(DEBUG_DRAW_UNSHADED);
BIND_ENUM_CONSTANT(DEBUG_DRAW_LIGHTING);
BIND_ENUM_CONSTANT(DEBUG_DRAW_OVERDRAW);
BIND_ENUM_CONSTANT(DEBUG_DRAW_WIREFRAME);
BIND_ENUM_CONSTANT(DEBUG_DRAW_NORMAL_BUFFER);
- BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_ALBEDO);
- BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_LIGHTING);
- BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_EMISSION);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_VOXEL_GI_ALBEDO);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_VOXEL_GI_LIGHTING);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_VOXEL_GI_EMISSION);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SHADOW_ATLAS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SCENE_LUMINANCE);
@@ -3637,6 +3722,7 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_SPOT_LIGHTS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_DECALS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_REFLECTION_PROBES);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_OCCLUDERS)
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
@@ -3667,7 +3753,7 @@ Viewport::Viewport() {
viewport = RenderingServer::get_singleton()->viewport_create();
texture_rid = RenderingServer::get_singleton()->viewport_get_texture(viewport);
- default_texture.instance();
+ default_texture.instantiate();
default_texture->vp = const_cast<Viewport *>(this);
viewport_textures.insert(default_texture.ptr());
default_texture->proxy = RS::get_singleton()->texture_proxy_create(texture_rid);
@@ -3711,16 +3797,6 @@ Viewport::~Viewport() {
/////////////////////////////////
-void SubViewport::set_use_xr(bool p_use_xr) {
- xr = p_use_xr;
-
- RS::get_singleton()->viewport_set_use_xr(get_viewport_rid(), xr);
-}
-
-bool SubViewport::is_using_xr() {
- return xr;
-}
-
void SubViewport::set_size(const Size2i &p_size) {
_set_size(p_size, _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
}
@@ -3793,9 +3869,6 @@ void SubViewport::_notification(int p_what) {
}
void SubViewport::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &SubViewport::set_use_xr);
- ClassDB::bind_method(D_METHOD("is_using_xr"), &SubViewport::is_using_xr);
-
ClassDB::bind_method(D_METHOD("set_size", "size"), &SubViewport::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &SubViewport::get_size);
@@ -3811,7 +3884,6 @@ void SubViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &SubViewport::set_clear_mode);
ClassDB::bind_method(D_METHOD("get_clear_mode"), &SubViewport::get_clear_mode);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "xr"), "set_use_xr", "is_using_xr");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_2d_override"), "set_size_2d_override", "get_size_2d_override");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "size_2d_override_stretch"), "set_size_2d_override_stretch", "is_size_2d_override_stretch_enabled");
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 2a0026a561..9c3df4c770 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -32,6 +32,7 @@
#define VIEWPORT_H
#include "core/math/transform_2d.h"
+#include "core/templates/pair.h"
#include "scene/main/node.h"
#include "scene/resources/texture.h"
#include "scene/resources/world_2d.h"
@@ -77,7 +78,7 @@ public:
virtual bool has_alpha() const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
ViewportTexture();
~ViewportTexture();
@@ -115,14 +116,17 @@ public:
enum RenderInfo {
RENDER_INFO_OBJECTS_IN_FRAME,
- RENDER_INFO_VERTICES_IN_FRAME,
- RENDER_INFO_MATERIAL_CHANGES_IN_FRAME,
- RENDER_INFO_SHADER_CHANGES_IN_FRAME,
- RENDER_INFO_SURFACE_CHANGES_IN_FRAME,
+ RENDER_INFO_PRIMITIVES_IN_FRAME,
RENDER_INFO_DRAW_CALLS_IN_FRAME,
RENDER_INFO_MAX
};
+ enum RenderInfoType {
+ RENDER_INFO_TYPE_VISIBLE,
+ RENDER_INFO_TYPE_SHADOW,
+ RENDER_INFO_TYPE_MAX
+ };
+
enum DebugDraw {
DEBUG_DRAW_DISABLED,
DEBUG_DRAW_UNSHADED,
@@ -130,9 +134,9 @@ public:
DEBUG_DRAW_OVERDRAW,
DEBUG_DRAW_WIREFRAME,
DEBUG_DRAW_NORMAL_BUFFER,
- DEBUG_DRAW_GI_PROBE_ALBEDO,
- DEBUG_DRAW_GI_PROBE_LIGHTING,
- DEBUG_DRAW_GI_PROBE_EMISSION,
+ DEBUG_DRAW_VOXEL_GI_ALBEDO,
+ DEBUG_DRAW_VOXEL_GI_LIGHTING,
+ DEBUG_DRAW_VOXEL_GI_EMISSION,
DEBUG_DRAW_SHADOW_ATLAS,
DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
DEBUG_DRAW_SCENE_LUMINANCE,
@@ -147,6 +151,7 @@ public:
DEBUG_DRAW_CLUSTER_SPOT_LIGHTS,
DEBUG_DRAW_CLUSTER_DECALS,
DEBUG_DRAW_CLUSTER_REFLECTION_PROBES,
+ DEBUG_DRAW_OCCLUDERS,
};
enum DefaultCanvasItemTextureFilter {
@@ -192,7 +197,7 @@ private:
Set<Listener3D *> listeners;
struct CameraOverrideData {
- Transform transform;
+ Transform3D transform;
enum Projection {
PROJECTION_PERSPECTIVE,
PROJECTION_ORTHOGONAL
@@ -209,7 +214,8 @@ private:
}
} camera_override;
- Camera3D *camera = nullptr;
+ Camera3D *camera_3d = nullptr;
+ Camera2D *camera_2d = nullptr;
Set<Camera3D *> cameras;
Set<CanvasLayer *> canvas_layers;
@@ -230,9 +236,10 @@ private:
Transform2D global_canvas_transform;
Transform2D stretch_transform;
- Size2i size;
+ 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;
@@ -252,11 +259,11 @@ private:
List<Ref<InputEvent>> physics_picking_events;
ObjectID physics_object_capture;
ObjectID physics_object_over;
- Transform physics_last_object_transform;
- Transform physics_last_camera_transform;
+ Transform3D physics_last_object_transform;
+ 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,7 +278,12 @@ private:
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;
@@ -286,6 +298,8 @@ private:
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);
@@ -304,6 +318,7 @@ private:
ScreenSpaceAA screen_space_aa = SCREEN_SPACE_AA_DISABLED;
bool use_debanding = false;
float lod_threshold = 1.0;
+ bool use_occlusion_culling = false;
Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures;
@@ -357,7 +372,7 @@ private:
Point2 drag_accum;
bool drag_attempted = false;
Variant drag_data;
- Control *drag_preview = nullptr;
+ ObjectID drag_preview_id;
float tooltip_timer = -1.0;
float tooltip_delay = 0.0;
Transform2D focus_inv_xform;
@@ -389,13 +404,10 @@ 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);
- void update_worlds();
-
_FORCE_INLINE_ Transform2D _get_input_pre_xform() const;
Ref<InputEvent> _make_input_local(const Ref<InputEvent> &ev);
@@ -415,6 +427,7 @@ private:
void _gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control);
void _gui_set_drag_preview(Control *p_base, Control *p_control);
+ Control *_gui_get_drag_preview();
void _gui_remove_focus_for_window(Node *p_window);
void _gui_remove_focus();
@@ -437,11 +450,14 @@ private:
void _listener_make_next_current(Listener3D *p_exclude);
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);
+ 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);
+
+ friend class Camera2D;
+ void _camera_2d_set(Camera2D *p_camera_2d);
friend class CanvasLayer;
void _canvas_layer_add(CanvasLayer *p_canvas_layer);
@@ -479,19 +495,19 @@ protected:
void _notification(int p_what);
void _process_picking();
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
public:
uint64_t get_processed_events_count() const { return event_count; }
Listener3D *get_listener() const;
- Camera3D *get_camera() const;
+ Camera3D *get_camera_3d() const;
+ Camera2D *get_camera_2d() const;
void enable_camera_override(bool p_enable);
bool is_camera_override_enabled() const;
- void set_camera_override_transform(const Transform &p_transform);
- Transform get_camera_override_transform() 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);
@@ -502,6 +518,9 @@ public:
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;
@@ -532,6 +551,9 @@ 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);
@@ -555,6 +577,9 @@ public:
void set_lod_threshold(float p_pixels);
float get_lod_threshold() const;
+ void set_use_occlusion_culling(bool p_us_occlusion_culling);
+ bool is_using_occlusion_culling() const;
+
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
@@ -579,12 +604,12 @@ public:
void gui_reset_canvas_sort_index();
int gui_get_canvas_sort_index();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_debug_draw(DebugDraw p_debug_draw);
DebugDraw get_debug_draw() const;
- int get_render_info(RenderInfo p_info);
+ int get_render_info(RenderInfoType p_type, RenderInfo p_info);
void set_snap_controls_to_pixels(bool p_enable);
bool is_snap_controls_to_pixels_enabled() const;
@@ -603,6 +628,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;
@@ -651,7 +678,6 @@ public:
private:
UpdateMode update_mode = UPDATE_WHEN_VISIBLE;
ClearMode clear_mode = CLEAR_MODE_ALWAYS;
- bool xr = false;
bool size_2d_override_stretch = false;
protected:
@@ -667,9 +693,6 @@ public:
void set_size_2d_override(const Size2i &p_size);
Size2i get_size_2d_override() const;
- void set_use_xr(bool p_use_xr);
- bool is_using_xr();
-
void set_size_2d_override_stretch(bool p_enable);
bool is_size_2d_override_stretch_enabled() const;
@@ -691,6 +714,7 @@ VARIANT_ENUM_CAST(Viewport::SDFScale);
VARIANT_ENUM_CAST(Viewport::SDFOversize);
VARIANT_ENUM_CAST(SubViewport::ClearMode);
VARIANT_ENUM_CAST(Viewport::RenderInfo);
+VARIANT_ENUM_CAST(Viewport::RenderInfoType);
VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureFilter);
VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureRepeat);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 8198fa41c5..bf7512e8eb 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -115,7 +115,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 +227,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(title, window_id);
+ DisplayServer::get_singleton()->window_set_title(tr(title), window_id);
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
_update_window_size();
@@ -312,39 +313,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 +542,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
@@ -759,6 +761,10 @@ void Window::_notification(int p_what) {
}
}
+ if (p_what == NOTIFICATION_TRANSLATION_CHANGED) {
+ child_controls_changed();
+ }
+
if (p_what == NOTIFICATION_EXIT_TREE) {
if (transient) {
_clear_transient();
@@ -826,6 +832,9 @@ bool Window::is_using_font_oversampling() const {
}
DisplayServer::WindowID Window::get_window_id() const {
+ if (embedder) {
+ return parent->get_window_id();
+ }
return window_id;
}
@@ -873,7 +882,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 {
@@ -890,12 +899,13 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
}
if (exclusive_child != nullptr) {
+ /*
Window *focus_target = exclusive_child;
focus_target->grab_focus();
while (focus_target->exclusive_child != nullptr) {
focus_target = focus_target->exclusive_child;
focus_target->grab_focus();
- }
+ }*/
if (!is_embedding_subwindows()) { //not embedding, no need for event
return;
@@ -915,7 +925,7 @@ void Window::_window_input_text(const String &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 {
@@ -1033,7 +1043,10 @@ 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();
if (p_screen_rect != Rect2i()) {
set_position(p_screen_rect.position);
@@ -1158,64 +1171,97 @@ Ref<Theme> Window::get_theme() const {
return theme;
}
-Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::get_icons(theme_owner, theme_owner_window, p_name, 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_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_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);
+ }
+ } else {
+ Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list);
+ }
+}
+
+Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
}
-Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, type);
+Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
-Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::get_fonts(theme_owner, theme_owner_window, p_name, type);
+Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
}
-int Window::get_theme_font_size(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::get_font_sizes(theme_owner, theme_owner_window, p_name, type);
+int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
-Color Window::get_theme_color(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::get_colors(theme_owner, theme_owner_window, p_name, type);
+Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
-int Window::get_theme_constant(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::get_constants(theme_owner, theme_owner_window, p_name, type);
+int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
-bool Window::has_theme_icon(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::has_icons(theme_owner, theme_owner_window, p_name, type);
+bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
}
-bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, type);
+bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
-bool Window::has_theme_font(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::has_fonts(theme_owner, theme_owner_window, p_name, type);
+bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
}
-bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::has_font_sizes(theme_owner, theme_owner_window, p_name, type);
+bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
-bool Window::has_theme_color(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::has_colors(theme_owner, theme_owner_window, p_name, type);
+bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
-bool Window::has_theme_constant(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::has_constants(theme_owner, theme_owner_window, p_name, type);
+bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
Rect2i Window::get_parent_rect() const {
@@ -1279,14 +1325,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();
@@ -1296,6 +1342,34 @@ bool Window::is_layout_rtl() const {
}
}
+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 (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ // Skip duplicate values.
+ if (unique_names.has(E->get())) {
+ continue;
+ }
+
+ hint_string += String(E->get()) + ",";
+ unique_names.append(E->get());
+ }
+
+ 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);
@@ -1350,6 +1424,8 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_embedded"), &Window::is_embedded);
+ ClassDB::bind_method(D_METHOD("get_contents_minimum_size"), &Window::get_contents_minimum_size);
+
ClassDB::bind_method(D_METHOD("set_content_scale_size", "size"), &Window::set_content_scale_size);
ClassDB::bind_method(D_METHOD("get_content_scale_size"), &Window::get_content_scale_size);
@@ -1371,19 +1447,22 @@ 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("get_theme_icon", "name", "type"), &Window::get_theme_icon, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "type"), &Window::get_theme_stylebox, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_font", "name", "type"), &Window::get_theme_font, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_font_size", "name", "type"), &Window::get_theme_font_size, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_color", "name", "type"), &Window::get_theme_color, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "type"), &Window::get_theme_constant, DEFVAL(""));
+ 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(""));
+ ClassDB::bind_method(D_METHOD("get_theme_font", "name", "theme_type"), &Window::get_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_font_size", "name", "theme_type"), &Window::get_theme_font_size, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_color", "name", "theme_type"), &Window::get_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "theme_type"), &Window::get_theme_constant, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_icon", "name", "type"), &Window::has_theme_icon, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "type"), &Window::has_theme_stylebox, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_font", "name", "type"), &Window::has_theme_font, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_font_size", "name", "type"), &Window::has_theme_font_size, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_color", "name", "type"), &Window::has_theme_color, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "type"), &Window::has_theme_constant, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_icon", "name", "theme_type"), &Window::has_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "theme_type"), &Window::has_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_font", "name", "theme_type"), &Window::has_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_font_size", "name", "theme_type"), &Window::has_theme_font_size, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Window::has_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Window::has_theme_constant, DEFVAL(""));
ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Window::set_layout_direction);
ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction);
@@ -1398,7 +1477,7 @@ void Window::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
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::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_GROUP("Flags", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
@@ -1415,10 +1494,11 @@ void Window::_bind_methods() {
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,CanvasItems,Viewport"), "set_content_scale_mode", "get_content_scale_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_aspect", PROPERTY_HINT_ENUM, "Ignore,Keep,KeepWidth,KeepHeight,Expand"), "set_content_scale_aspect", "get_content_scale_aspect");
- ADD_GROUP("Theme", "");
+ 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_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation");
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 38846ed00e..e92b5e22ed 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -130,6 +130,7 @@ private:
Ref<Theme> theme;
Control *theme_owner = nullptr;
Window *theme_owner_window = nullptr;
+ StringName theme_type_variation;
Viewport *embedder = nullptr;
@@ -150,6 +151,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;
@@ -241,6 +243,10 @@ public:
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() 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;
void grab_focus();
@@ -252,19 +258,19 @@ public:
Rect2i get_usable_parent_rect() const;
- Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
- Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
- Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
- int get_theme_font_size(const StringName &p_name, const StringName &p_type = StringName()) const;
- Color get_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const;
- int get_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
-
- bool has_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_theme_font_size(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ int get_theme_font_size(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Color get_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ int get_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+
+ bool has_theme_icon(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_font(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_font_size(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
Rect2i get_parent_rect() const;
virtual DisplayServer::WindowID get_window_id() const override;