summaryrefslogtreecommitdiff
path: root/scene/main
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main')
-rw-r--r--scene/main/canvas_item.cpp943
-rw-r--r--scene/main/canvas_item.h315
-rw-r--r--scene/main/canvas_layer.cpp105
-rw-r--r--scene/main/canvas_layer.h28
-rw-r--r--scene/main/http_request.cpp338
-rw-r--r--scene/main/http_request.h61
-rw-r--r--scene/main/instance_placeholder.cpp56
-rw-r--r--scene/main/instance_placeholder.h5
-rw-r--r--scene/main/node.cpp1856
-rw-r--r--scene/main/node.h282
-rw-r--r--scene/main/resource_preloader.cpp22
-rw-r--r--scene/main/resource_preloader.h5
-rw-r--r--scene/main/scene_tree.cpp766
-rw-r--r--scene/main/scene_tree.h141
-rw-r--r--scene/main/shader_globals_override.cpp75
-rw-r--r--scene/main/shader_globals_override.h37
-rw-r--r--scene/main/timer.cpp99
-rw-r--r--scene/main/timer.h35
-rw-r--r--scene/main/viewport.cpp2928
-rw-r--r--scene/main/viewport.h452
-rw-r--r--scene/main/window.cpp623
-rw-r--r--scene/main/window.h85
22 files changed, 4632 insertions, 4625 deletions
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 2eacad68c3..64b169b1fb 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,300 +30,17 @@
#include "canvas_item.h"
-#include "core/input/input_filter.h"
-#include "core/message_queue.h"
-#include "core/method_bind_ext.gen.inc"
+#include "core/object/message_queue.h"
+#include "scene/2d/canvas_group.h"
#include "scene/main/canvas_layer.h"
-#include "scene/main/viewport.h"
#include "scene/main/window.h"
+#include "scene/resources/canvas_item_material.h"
#include "scene/resources/font.h"
+#include "scene/resources/multimesh.h"
#include "scene/resources/style_box.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/world_2d.h"
#include "scene/scene_string_names.h"
-#include "servers/rendering_server.h"
-Mutex CanvasItemMaterial::material_mutex;
-SelfList<CanvasItemMaterial>::List *CanvasItemMaterial::dirty_materials = nullptr;
-Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
-CanvasItemMaterial::ShaderNames *CanvasItemMaterial::shader_names = nullptr;
-
-void CanvasItemMaterial::init_shaders() {
-
- dirty_materials = memnew(SelfList<CanvasItemMaterial>::List);
-
- shader_names = memnew(ShaderNames);
-
- shader_names->particles_anim_h_frames = "particles_anim_h_frames";
- shader_names->particles_anim_v_frames = "particles_anim_v_frames";
- shader_names->particles_anim_loop = "particles_anim_loop";
-}
-
-void CanvasItemMaterial::finish_shaders() {
-
- memdelete(dirty_materials);
- memdelete(shader_names);
- dirty_materials = nullptr;
-}
-
-void CanvasItemMaterial::_update_shader() {
-
- dirty_materials->remove(&element);
-
- MaterialKey mk = _compute_key();
- if (mk.key == current_key.key)
- return; //no update required in the end
-
- if (shader_map.has(current_key)) {
- shader_map[current_key].users--;
- if (shader_map[current_key].users == 0) {
- //deallocate shader, as it's no longer in use
- RS::get_singleton()->free(shader_map[current_key].shader);
- shader_map.erase(current_key);
- }
- }
-
- current_key = mk;
-
- if (shader_map.has(mk)) {
-
- RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
- shader_map[mk].users++;
- return;
- }
-
- //must create a shader!
-
- String code = "shader_type canvas_item;\nrender_mode ";
- switch (blend_mode) {
- case BLEND_MODE_MIX: code += "blend_mix"; break;
- case BLEND_MODE_ADD: code += "blend_add"; break;
- case BLEND_MODE_SUB: code += "blend_sub"; break;
- case BLEND_MODE_MUL: code += "blend_mul"; break;
- case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break;
- case BLEND_MODE_DISABLED: code += "blend_disabled"; break;
- }
-
- switch (light_mode) {
- case LIGHT_MODE_NORMAL: break;
- case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
- case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
- }
-
- code += ";\n";
-
- if (particles_animation) {
-
- code += "uniform int particles_anim_h_frames;\n";
- code += "uniform int particles_anim_v_frames;\n";
- code += "uniform bool particles_anim_loop;\n";
-
- code += "void vertex() {\n";
-
- code += "\tfloat h_frames = float(particles_anim_h_frames);\n";
- code += "\tfloat v_frames = float(particles_anim_v_frames);\n";
-
- code += "\tVERTEX.xy /= vec2(h_frames, v_frames);\n";
-
- code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n";
- code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
- code += "\tif (!particles_anim_loop) {\n";
- code += "\t\tparticle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
- code += "\t} else {\n";
- code += "\t\tparticle_frame = mod(particle_frame, particle_total_frames);\n";
- code += "\t}";
- code += "\tUV /= vec2(h_frames, v_frames);\n";
- code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n";
- code += "}\n";
- }
-
- ShaderData shader_data;
- shader_data.shader = RS::get_singleton()->shader_create();
- shader_data.users = 1;
-
- RS::get_singleton()->shader_set_code(shader_data.shader, code);
-
- shader_map[mk] = shader_data;
-
- RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
-}
-
-void CanvasItemMaterial::flush_changes() {
-
- MutexLock lock(material_mutex);
-
- while (dirty_materials->first()) {
-
- dirty_materials->first()->self()->_update_shader();
- }
-}
-
-void CanvasItemMaterial::_queue_shader_change() {
-
- MutexLock lock(material_mutex);
-
- if (!element.in_list()) {
- dirty_materials->add(&element);
- }
-}
-
-bool CanvasItemMaterial::_is_shader_dirty() const {
-
- MutexLock lock(material_mutex);
-
- return element.in_list();
-}
-void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) {
-
- blend_mode = p_blend_mode;
- _queue_shader_change();
-}
-
-CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const {
- return blend_mode;
-}
-
-void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) {
-
- light_mode = p_light_mode;
- _queue_shader_change();
-}
-
-CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
-
- return light_mode;
-}
-
-void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) {
- particles_animation = p_particles_anim;
- _queue_shader_change();
- _change_notify();
-}
-
-bool CanvasItemMaterial::get_particles_animation() const {
- return particles_animation;
-}
-
-void CanvasItemMaterial::set_particles_anim_h_frames(int p_frames) {
-
- particles_anim_h_frames = p_frames;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
-}
-
-int CanvasItemMaterial::get_particles_anim_h_frames() const {
-
- return particles_anim_h_frames;
-}
-void CanvasItemMaterial::set_particles_anim_v_frames(int p_frames) {
-
- particles_anim_v_frames = p_frames;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
-}
-
-int CanvasItemMaterial::get_particles_anim_v_frames() const {
-
- return particles_anim_v_frames;
-}
-
-void CanvasItemMaterial::set_particles_anim_loop(bool p_loop) {
-
- particles_anim_loop = p_loop;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
-}
-
-bool CanvasItemMaterial::get_particles_anim_loop() const {
-
- return particles_anim_loop;
-}
-
-void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("particles_anim_") && !particles_animation) {
- property.usage = 0;
- }
-}
-
-RID CanvasItemMaterial::get_shader_rid() const {
-
- ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
- return shader_map[current_key].shader;
-}
-
-Shader::Mode CanvasItemMaterial::get_shader_mode() const {
-
- return Shader::MODE_CANVAS_ITEM;
-}
-
-void CanvasItemMaterial::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode);
- ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode);
-
- ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode);
- ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode);
-
- ClassDB::bind_method(D_METHOD("set_particles_animation", "particles_anim"), &CanvasItemMaterial::set_particles_animation);
- ClassDB::bind_method(D_METHOD("get_particles_animation"), &CanvasItemMaterial::get_particles_animation);
-
- ClassDB::bind_method(D_METHOD("set_particles_anim_h_frames", "frames"), &CanvasItemMaterial::set_particles_anim_h_frames);
- ClassDB::bind_method(D_METHOD("get_particles_anim_h_frames"), &CanvasItemMaterial::get_particles_anim_h_frames);
-
- ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &CanvasItemMaterial::set_particles_anim_v_frames);
- ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &CanvasItemMaterial::get_particles_anim_v_frames);
-
- ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &CanvasItemMaterial::set_particles_anim_loop);
- ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &CanvasItemMaterial::get_particles_anim_loop);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_animation"), "set_particles_animation", "get_particles_animation");
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_h_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_h_frames", "get_particles_anim_h_frames");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_v_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_v_frames", "get_particles_anim_v_frames");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_anim_loop"), "set_particles_anim_loop", "get_particles_anim_loop");
-
- BIND_ENUM_CONSTANT(BLEND_MODE_MIX);
- BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
- BIND_ENUM_CONSTANT(BLEND_MODE_SUB);
- BIND_ENUM_CONSTANT(BLEND_MODE_MUL);
- BIND_ENUM_CONSTANT(BLEND_MODE_PREMULT_ALPHA);
-
- BIND_ENUM_CONSTANT(LIGHT_MODE_NORMAL);
- BIND_ENUM_CONSTANT(LIGHT_MODE_UNSHADED);
- BIND_ENUM_CONSTANT(LIGHT_MODE_LIGHT_ONLY);
-}
-
-CanvasItemMaterial::CanvasItemMaterial() :
- element(this) {
-
- blend_mode = BLEND_MODE_MIX;
- light_mode = LIGHT_MODE_NORMAL;
- particles_animation = false;
-
- set_particles_anim_h_frames(1);
- set_particles_anim_v_frames(1);
- set_particles_anim_loop(false);
-
- current_key.key = 0;
- current_key.invalid_key = 1;
- _queue_shader_change();
-}
-
-CanvasItemMaterial::~CanvasItemMaterial() {
-
- MutexLock lock(material_mutex);
-
- if (shader_map.has(current_key)) {
- shader_map[current_key].users--;
- if (shader_map[current_key].users == 0) {
- //deallocate shader, as it's no longer in use
- RS::get_singleton()->free(shader_map[current_key].shader);
- shader_map.erase(current_key);
- }
-
- RS::get_singleton()->material_set_shader(_get_material(), RID());
- }
-}
-
-///////////////////////////////////////////////////////////////////
#ifdef TOOLS_ENABLED
bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
if (_edit_use_rect()) {
@@ -339,15 +56,16 @@ Transform2D CanvasItem::_edit_get_transform() const {
#endif
bool CanvasItem::is_visible_in_tree() const {
-
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
return false;
+ }
const CanvasItem *p = this;
while (p) {
- if (!p->visible)
+ if (!p->visible) {
return false;
+ }
if (p->window && !p->window->is_visible()) {
return false;
}
@@ -358,57 +76,57 @@ bool CanvasItem::is_visible_in_tree() const {
}
void CanvasItem::_propagate_visibility_changed(bool p_visible) {
-
if (p_visible && first_draw) { //avoid propagating it twice
first_draw = false;
}
notification(NOTIFICATION_VISIBILITY_CHANGED);
- if (p_visible)
+ if (p_visible) {
update(); //todo optimize
- else
- emit_signal(SceneStringNames::get_singleton()->hide);
+ } else {
+ emit_signal(SceneStringNames::get_singleton()->hidden);
+ }
_block();
for (int i = 0; i < get_child_count(); i++) {
-
CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
- if (c && c->visible) //should the toplevels stop propagation? i think so but..
+ if (c && c->visible) { //should the top_levels stop propagation? i think so but..
c->_propagate_visibility_changed(p_visible);
+ }
}
_unblock();
}
void CanvasItem::show() {
-
- if (visible)
+ if (visible) {
return;
+ }
visible = true;
RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, true);
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
return;
+ }
_propagate_visibility_changed(true);
- _change_notify("visible");
}
void CanvasItem::hide() {
-
- if (!visible)
+ if (!visible) {
return;
+ }
visible = false;
RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, false);
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
return;
+ }
_propagate_visibility_changed(false);
- _change_notify("visible");
}
CanvasItem *CanvasItem::current_item_drawn = nullptr;
@@ -417,7 +135,6 @@ CanvasItem *CanvasItem::get_current_item_drawn() {
}
void CanvasItem::_update_callback() {
-
if (!is_inside_tree()) {
pending_update = false;
return;
@@ -434,9 +151,7 @@ void CanvasItem::_update_callback() {
current_item_drawn = this;
notification(NOTIFICATION_DRAW);
emit_signal(SceneStringNames::get_singleton()->draw);
- if (get_script_instance()) {
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw, nullptr, 0);
- }
+ GDVIRTUAL_CALL(_draw);
current_item_drawn = nullptr;
drawing = false;
}
@@ -445,13 +160,13 @@ void CanvasItem::_update_callback() {
}
Transform2D CanvasItem::get_global_transform_with_canvas() const {
-
- if (canvas_layer)
+ if (canvas_layer) {
return canvas_layer->get_transform() * get_global_transform();
- else if (is_inside_tree())
+ } else if (is_inside_tree()) {
return get_viewport()->get_canvas_transform() * get_global_transform();
- else
+ } else {
return get_global_transform();
+ }
}
Transform2D CanvasItem::get_screen_transform() const {
@@ -474,12 +189,12 @@ Transform2D CanvasItem::get_global_transform() const {
ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
#endif
if (global_invalid) {
-
const CanvasItem *pi = get_parent_item();
- if (pi)
+ if (pi) {
global_transform = pi->get_global_transform() * get_transform();
- else
+ } else {
global_transform = get_transform();
+ }
global_invalid = false;
}
@@ -487,27 +202,25 @@ Transform2D CanvasItem::get_global_transform() const {
return global_transform;
}
-void CanvasItem::_toplevel_raise_self() {
-
- if (!is_inside_tree())
+void CanvasItem::_top_level_raise_self() {
+ if (!is_inside_tree()) {
return;
+ }
- if (canvas_layer)
+ if (canvas_layer) {
RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, canvas_layer->get_sort_index());
- else
+ } else {
RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_viewport()->gui_get_canvas_sort_index());
+ }
}
void CanvasItem::_enter_canvas() {
-
- if ((!Object::cast_to<CanvasItem>(get_parent())) || toplevel) {
-
+ if ((!Object::cast_to<CanvasItem>(get_parent())) || top_level) {
Node *n = this;
canvas_layer = nullptr;
while (n) {
-
canvas_layer = Object::cast_to<CanvasLayer>(n);
if (canvas_layer) {
break;
@@ -519,25 +232,26 @@ void CanvasItem::_enter_canvas() {
}
RID canvas;
- if (canvas_layer)
+ if (canvas_layer) {
canvas = canvas_layer->get_canvas();
- else
+ } else {
canvas = get_viewport()->find_world_2d()->get_canvas();
+ }
RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
group = "root_canvas" + itos(canvas.get_id());
add_to_group(group);
- if (canvas_layer)
+ if (canvas_layer) {
canvas_layer->reset_sort_index();
- else
+ } else {
get_viewport()->gui_reset_canvas_sort_index();
+ }
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, SNAME("_top_level_raise_self"));
} else {
-
CanvasItem *parent = get_parent_item();
canvas_layer = parent->canvas_layer;
RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, parent->get_canvas_item());
@@ -551,18 +265,15 @@ void CanvasItem::_enter_canvas() {
}
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) {
-
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
-
_update_texture_filter_changed(false);
_update_texture_repeat_changed(false);
@@ -570,8 +281,9 @@ void CanvasItem::_notification(int p_what) {
Node *parent = get_parent();
if (parent) {
CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
- if (ci)
+ if (ci) {
C = ci->children_items.push_back(this);
+ }
if (!ci) {
//look for a window
Viewport *viewport = nullptr;
@@ -598,12 +310,12 @@ void CanvasItem::_notification(int p_what) {
}
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
-
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
break;
+ }
- if (group != "") {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
+ if (group != StringName()) {
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_top_level_raise_self");
} else {
CanvasItem *p = get_parent_item();
ERR_FAIL_COND(!p);
@@ -612,8 +324,9 @@ void CanvasItem::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
- if (xform_change.in_list())
+ if (xform_change.in_list()) {
get_tree()->xform_change_list.remove(&xform_change);
+ }
_exit_canvas();
if (C) {
Object::cast_to<CanvasItem>(get_parent())->children_items.erase(C);
@@ -626,160 +339,152 @@ void CanvasItem::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW:
case NOTIFICATION_TRANSFORM_CHANGED: {
-
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
-
emit_signal(SceneStringNames::get_singleton()->visibility_changed);
} break;
}
}
void CanvasItem::set_visible(bool p_visible) {
-
- if (p_visible)
+ if (p_visible) {
show();
- else
+ } else {
hide();
+ }
}
void CanvasItem::_window_visibility_changed() {
-
if (visible) {
_propagate_visibility_changed(window->is_visible());
}
}
bool CanvasItem::is_visible() const {
-
return visible;
}
void CanvasItem::update() {
-
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
return;
- if (pending_update)
+ }
+ if (pending_update) {
return;
+ }
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) {
-
- if (modulate == p_modulate)
+ if (modulate == p_modulate) {
return;
+ }
modulate = p_modulate;
RenderingServer::get_singleton()->canvas_item_set_modulate(canvas_item, modulate);
}
-Color CanvasItem::get_modulate() const {
+Color CanvasItem::get_modulate() const {
return modulate;
}
-void CanvasItem::set_as_toplevel(bool p_toplevel) {
-
- if (toplevel == p_toplevel)
+void CanvasItem::set_as_top_level(bool p_top_level) {
+ if (top_level == p_top_level) {
return;
+ }
if (!is_inside_tree()) {
- toplevel = p_toplevel;
+ top_level = p_top_level;
return;
}
_exit_canvas();
- toplevel = p_toplevel;
+ top_level = p_top_level;
_enter_canvas();
-}
-bool CanvasItem::is_set_as_toplevel() const {
+ _notify_transform();
+}
- return toplevel;
+bool CanvasItem::is_set_as_top_level() const {
+ return top_level;
}
CanvasItem *CanvasItem::get_parent_item() const {
-
- if (toplevel)
+ if (top_level) {
return nullptr;
+ }
return Object::cast_to<CanvasItem>(get_parent());
}
void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
-
- if (self_modulate == p_self_modulate)
+ if (self_modulate == p_self_modulate) {
return;
+ }
self_modulate = p_self_modulate;
RenderingServer::get_singleton()->canvas_item_set_self_modulate(canvas_item, self_modulate);
}
-Color CanvasItem::get_self_modulate() const {
+Color CanvasItem::get_self_modulate() const {
return self_modulate;
}
void CanvasItem::set_light_mask(int p_light_mask) {
-
- if (light_mask == p_light_mask)
+ if (light_mask == p_light_mask) {
return;
+ }
light_mask = p_light_mask;
RS::get_singleton()->canvas_item_set_light_mask(canvas_item, p_light_mask);
}
int CanvasItem::get_light_mask() const {
-
return light_mask;
}
void CanvasItem::item_rect_changed(bool p_size_changed) {
-
- if (p_size_changed)
+ if (p_size_changed) {
update();
+ }
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) {
-
+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;
colors.push_back(p_color);
- RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width);
+ 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) {
-
+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);
+ 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) {
-
+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);
+ 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;
@@ -787,15 +492,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) {
@@ -807,7 +510,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 {
@@ -841,34 +544,37 @@ 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);
}
-void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
+void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw(canvas_item, p_pos, p_modulate, false, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+ p_texture->draw(canvas_item, p_pos, p_modulate, false);
}
-void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
+void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+ p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose);
+}
+
+void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) {
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_FAIL_COND(p_texture.is_null());
+ p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv);
}
-void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, bool p_clip_uv, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat), p_clip_uv);
+ RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range);
}
void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
@@ -878,18 +584,15 @@ 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, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+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();
- RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
- RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+ 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);
@@ -898,78 +601,73 @@ void CanvasItem::draw_set_transform(const Point2 &p_offset, float p_rot, const S
}
void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
-
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
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.");
-void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+ 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.");
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+ RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid);
}
-void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
+void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, 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.");
Vector<Color> colors;
colors.push_back(p_color);
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
- RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+ RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid);
}
-void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, const Transform2D &p_transform, const Color &p_modulate, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
+void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform, const Color &p_modulate) {
ERR_FAIL_COND(p_mesh.is_null());
RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- RenderingServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+ RenderingServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid);
}
-void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture) {
ERR_FAIL_COND(p_multimesh.is_null());
RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
- RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+ 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, const Color &p_modulate, int p_clip_w) {
-
+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(canvas_item, p_pos, p_text, p_modulate, p_clip_w);
+ 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);
}
-float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, const Color &p_modulate) {
-
- ERR_FAIL_COND_V_MSG(!drawing, 0, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+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);
+}
- ERR_FAIL_COND_V(p_char.length() != 1, 0);
- ERR_FAIL_COND_V(p_font.is_null(), 0);
+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);
- if (p_font->has_outline()) {
- p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], Color(1, 1, 1), true);
- }
- return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], p_modulate);
+ return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.get_data()[0], p_size, p_modulate, p_outline_size, p_outline_modulate);
}
void CanvasItem::_notify_transform(CanvasItem *p_node) {
-
/* This check exists to avoid re-propagating the transform
* notification down the tree on dirty nodes. It provides
* optimization by avoiding redundancy (nodes are dirty, will get the
@@ -984,38 +682,36 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) {
if (p_node->notify_transform && !p_node->xform_change.in_list()) {
if (!p_node->block_transform_notify) {
- if (p_node->is_inside_tree())
+ if (p_node->is_inside_tree()) {
get_tree()->xform_change_list.add(&p_node->xform_change);
+ }
}
}
- for (List<CanvasItem *>::Element *E = p_node->children_items.front(); E; E = E->next()) {
-
- CanvasItem *ci = E->get();
- if (ci->toplevel)
+ for (CanvasItem *ci : p_node->children_items) {
+ if (ci->top_level) {
continue;
+ }
_notify_transform(ci);
}
}
Rect2 CanvasItem::get_viewport_rect() const {
-
ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
return get_viewport()->get_visible_rect();
}
RID CanvasItem::get_canvas() const {
-
ERR_FAIL_COND_V(!is_inside_tree(), RID());
- if (canvas_layer)
+ if (canvas_layer) {
return canvas_layer->get_canvas();
- else
+ } else {
return get_viewport()->find_world_2d()->get_canvas();
+ }
}
ObjectID CanvasItem::get_canvas_layer_instance_id() const {
-
if (canvas_layer) {
return canvas_layer->get_instance_id();
} else {
@@ -1023,10 +719,9 @@ ObjectID CanvasItem::get_canvas_layer_instance_id() const {
}
}
-CanvasItem *CanvasItem::get_toplevel() const {
-
+CanvasItem *CanvasItem::get_top_level() const {
CanvasItem *ci = const_cast<CanvasItem *>(this);
- while (!ci->toplevel && Object::cast_to<CanvasItem>(ci->get_parent())) {
+ while (!ci->top_level && Object::cast_to<CanvasItem>(ci->get_parent())) {
ci = Object::cast_to<CanvasItem>(ci->get_parent());
}
@@ -1034,10 +729,9 @@ CanvasItem *CanvasItem::get_toplevel() const {
}
Ref<World2D> CanvasItem::get_world_2d() const {
-
ERR_FAIL_COND_V(!is_inside_tree(), Ref<World2D>());
- CanvasItem *tl = get_toplevel();
+ CanvasItem *tl = get_top_level();
if (tl->get_viewport()) {
return tl->get_viewport()->find_world_2d();
@@ -1047,7 +741,6 @@ Ref<World2D> CanvasItem::get_world_2d() const {
}
RID CanvasItem::get_viewport_rid() const {
-
ERR_FAIL_COND_V(!is_inside_tree(), RID());
return get_viewport()->get_viewport_rid();
}
@@ -1057,51 +750,45 @@ void CanvasItem::set_block_transform_notify(bool p_enable) {
}
bool CanvasItem::is_block_transform_notify_enabled() const {
-
return block_transform_notify;
}
void CanvasItem::set_draw_behind_parent(bool p_enable) {
-
- if (behind == p_enable)
+ if (behind == p_enable) {
return;
+ }
behind = p_enable;
RenderingServer::get_singleton()->canvas_item_set_draw_behind_parent(canvas_item, behind);
}
bool CanvasItem::is_draw_behind_parent_enabled() const {
-
return behind;
}
void CanvasItem::set_material(const Ref<Material> &p_material) {
-
material = p_material;
RID rid;
- if (material.is_valid())
+ if (material.is_valid()) {
rid = material->get_rid();
+ }
RS::get_singleton()->canvas_item_set_material(canvas_item, rid);
- _change_notify(); //properties for material exposed
+ notify_property_list_changed(); //properties for material exposed
}
void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
-
use_parent_material = p_use_parent_material;
RS::get_singleton()->canvas_item_set_use_parent_material(canvas_item, p_use_parent_material);
}
bool CanvasItem::get_use_parent_material() const {
-
return use_parent_material;
}
Ref<Material> CanvasItem::get_material() const {
-
return material;
}
Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) const {
-
ERR_FAIL_COND_V(!is_inside_tree(), screen_point);
Transform2D local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();
@@ -1110,7 +797,6 @@ Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) cons
}
Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const {
-
ERR_FAIL_COND_V(p_event.is_null(), p_event);
ERR_FAIL_COND_V(!is_inside_tree(), p_event);
@@ -1118,13 +804,11 @@ Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) con
}
Vector2 CanvasItem::get_global_mouse_position() const {
-
ERR_FAIL_COND_V(!get_viewport(), Vector2());
return get_canvas_transform().affine_inverse().xform(get_viewport()->get_mouse_position());
}
Vector2 CanvasItem::get_local_mouse_position() const {
-
ERR_FAIL_COND_V(!get_viewport(), Vector2());
return get_global_transform().affine_inverse().xform(get_global_mouse_position());
@@ -1142,8 +826,7 @@ void CanvasItem::force_update_transform() {
}
void CanvasItem::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_toplevel_raise_self"), &CanvasItem::_toplevel_raise_self);
+ ClassDB::bind_method(D_METHOD("_top_level_raise_self"), &CanvasItem::_top_level_raise_self);
ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback);
#ifdef TOOLS_ENABLED
@@ -1175,8 +858,8 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("update"), &CanvasItem::update);
- ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &CanvasItem::set_as_toplevel);
- ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &CanvasItem::is_set_as_toplevel);
+ ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &CanvasItem::set_as_top_level);
+ ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &CanvasItem::is_set_as_top_level);
ClassDB::bind_method(D_METHOD("set_light_mask", "light_mask"), &CanvasItem::set_light_mask);
ClassDB::bind_method(D_METHOD("get_light_mask"), &CanvasItem::get_light_mask);
@@ -1194,27 +877,30 @@ void CanvasItem::_bind_methods() {
//ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width"), &CanvasItem::draw_line, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width"), &CanvasItem::draw_polyline, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width"), &CanvasItem::draw_arc, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
- ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "clip_uv", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(true), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0));
ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
- ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1, 1)));
- ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "specular_map", "specular_shininess", "transform", "modulate", "texture_filter", "texture_repeat"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-
- ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
+ ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()));
+ ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()));
+ ClassDB::bind_method(D_METHOD("draw_string", "font", "pos", "text", "align", "width", "size", "modulate", "outline_size", "outline_modulate", "flags"), &CanvasItem::draw_string, DEFVAL(HALIGN_LEFT), DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND));
+ ClassDB::bind_method(D_METHOD("draw_multiline_string", "font", "pos", "text", "align", "width", "max_lines", "size", "modulate", "outline_size", "outline_modulate", "flags"), &CanvasItem::draw_multiline_string, DEFVAL(HALIGN_LEFT), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND));
+ ClassDB::bind_method(D_METHOD("draw_char", "font", "pos", "char", "next", "size", "modulate", "outline_size", "outline_modulate"), &CanvasItem::draw_char, DEFVAL(""), DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)));
+ ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "transform", "modulate"), &CanvasItem::draw_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1, 1)));
+ 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);
@@ -1250,30 +936,33 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
- BIND_VMETHOD(MethodInfo("_draw"));
+ ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children);
+ ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children);
+
+ GDVIRTUAL_BIND(_draw);
ADD_GROUP("Visibility", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
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, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility
+ 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, "", 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, "ParentNode,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "ParentNode,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
+ 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");
- //exporting these things doesn't really make much sense i think
- // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toplevel", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_as_toplevel", "is_set_as_toplevel");
// ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled");
ADD_SIGNAL(MethodInfo("draw"));
ADD_SIGNAL(MethodInfo("visibility_changed"));
- ADD_SIGNAL(MethodInfo("hide"));
+ ADD_SIGNAL(MethodInfo("hidden"));
ADD_SIGNAL(MethodInfo("item_rect_changed"));
BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
@@ -1299,23 +988,21 @@ void CanvasItem::_bind_methods() {
}
Transform2D CanvasItem::get_canvas_transform() const {
-
ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
- if (canvas_layer)
+ if (canvas_layer) {
return canvas_layer->get_transform();
- else if (Object::cast_to<CanvasItem>(get_parent()))
+ } else if (Object::cast_to<CanvasItem>(get_parent())) {
return Object::cast_to<CanvasItem>(get_parent())->get_canvas_transform();
- else
+ } else {
return get_viewport()->get_canvas_transform();
+ }
}
Transform2D CanvasItem::get_viewport_transform() const {
-
ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
if (canvas_layer) {
-
if (get_viewport()) {
return get_viewport()->get_final_transform() * canvas_layer->get_transform();
} else {
@@ -1336,8 +1023,9 @@ bool CanvasItem::is_local_transform_notification_enabled() const {
}
void CanvasItem::set_notify_transform(bool p_enable) {
- if (notify_transform == p_enable)
+ if (notify_transform == p_enable) {
return;
+ }
notify_transform = p_enable;
@@ -1352,15 +1040,14 @@ bool CanvasItem::is_transform_notification_enabled() const {
}
int CanvasItem::get_canvas_layer() const {
-
- if (canvas_layer)
+ if (canvas_layer) {
return canvas_layer->get_layer();
- else
+ } else {
return 0;
+ }
}
void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
-
if (!is_inside_tree()) {
return;
}
@@ -1370,15 +1057,7 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
if (parent_item) {
texture_filter_cache = parent_item->texture_filter_cache;
} else {
- //from viewport
- switch (get_viewport()->get_default_canvas_item_texture_filter()) {
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; break;
- default: {
- }
- }
+ texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
}
} else {
texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
@@ -1387,9 +1066,9 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
update();
if (p_propagate) {
- for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
- if (!E->get()->toplevel && E->get()->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
- E->get()->_update_texture_filter_changed(true);
+ for (CanvasItem *E : children_items) {
+ if (!E->top_level && E->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
+ E->_update_texture_filter_changed(true);
}
}
}
@@ -1402,6 +1081,7 @@ void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
}
texture_filter = p_texture_filter;
_update_texture_filter_changed(true);
+ notify_property_list_changed();
}
CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
@@ -1409,7 +1089,6 @@ CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
}
void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
-
if (!is_inside_tree()) {
return;
}
@@ -1419,14 +1098,7 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
if (parent_item) {
texture_repeat_cache = parent_item->texture_repeat_cache;
} else {
- //from viewport
- switch (get_viewport()->get_default_canvas_item_texture_repeat()) {
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR; break;
- default: {
- }
- }
+ texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
}
} else {
texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
@@ -1434,9 +1106,9 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
update();
if (p_propagate) {
- for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
- if (!E->get()->toplevel && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
- E->get()->_update_texture_repeat_changed(true);
+ for (CanvasItem *E : children_items) {
+ if (!E->top_level && E->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
+ E->_update_texture_repeat_changed(true);
}
}
}
@@ -1449,6 +1121,23 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
}
texture_repeat = p_texture_repeat;
_update_texture_repeat_changed(true);
+ notify_property_list_changed();
+}
+
+void CanvasItem::set_clip_children(bool p_enabled) {
+ if (clip_children == p_enabled) {
+ return;
+ }
+ clip_children = p_enabled;
+
+ if (Object::cast_to<CanvasGroup>(this) != nullptr) {
+ //avoid accidental bugs, make this not work on CanvasGroup
+ return;
+ }
+ RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), clip_children ? RS::CANVAS_GROUP_MODE_OPAQUE : RS::CANVAS_GROUP_MODE_DISABLED);
+}
+bool CanvasItem::is_clipping_children() const {
+ return clip_children;
}
CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
@@ -1457,33 +1146,163 @@ CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
CanvasItem::CanvasItem() :
xform_change(this) {
-
- window = nullptr;
canvas_item = RenderingServer::get_singleton()->canvas_item_create();
- visible = true;
- pending_update = false;
- modulate = Color(1, 1, 1, 1);
- self_modulate = Color(1, 1, 1, 1);
- toplevel = false;
- first_draw = false;
- drawing = false;
- behind = false;
- block_transform_notify = false;
- canvas_layer = nullptr;
- use_parent_material = false;
- global_invalid = true;
- notify_local_transform = false;
- notify_transform = false;
- light_mask = 1;
- texture_repeat = TEXTURE_REPEAT_PARENT_NODE;
- texture_filter = TEXTURE_FILTER_PARENT_NODE;
- texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
- texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
-
- C = nullptr;
}
CanvasItem::~CanvasItem() {
-
RenderingServer::get_singleton()->free(canvas_item);
}
+
+///////////////////////////////////////////////////////////////////
+
+void CanvasTexture::set_diffuse_texture(const Ref<Texture2D> &p_diffuse) {
+ 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();
+ RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE, tex_rid);
+ emit_changed();
+}
+Ref<Texture2D> CanvasTexture::get_diffuse_texture() const {
+ return diffuse_texture;
+}
+
+void CanvasTexture::set_normal_texture(const Ref<Texture2D> &p_normal) {
+ 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);
+}
+Ref<Texture2D> CanvasTexture::get_normal_texture() const {
+ return normal_texture;
+}
+
+void CanvasTexture::set_specular_texture(const Ref<Texture2D> &p_specular) {
+ 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;
+}
+
+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(real_t p_shininess) {
+ shininess = p_shininess;
+ RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
+}
+
+real_t CanvasTexture::get_specular_shininess() const {
+ return shininess;
+}
+
+void CanvasTexture::set_texture_filter(CanvasItem::TextureFilter p_filter) {
+ texture_filter = p_filter;
+ RS::get_singleton()->canvas_texture_set_texture_filter(canvas_texture, RS::CanvasItemTextureFilter(p_filter));
+}
+CanvasItem::TextureFilter CanvasTexture::get_texture_filter() const {
+ return texture_filter;
+}
+
+void CanvasTexture::set_texture_repeat(CanvasItem::TextureRepeat p_repeat) {
+ texture_repeat = p_repeat;
+ RS::get_singleton()->canvas_texture_set_texture_repeat(canvas_texture, RS::CanvasItemTextureRepeat(p_repeat));
+}
+CanvasItem::TextureRepeat CanvasTexture::get_texture_repeat() const {
+ return texture_repeat;
+}
+
+int CanvasTexture::get_width() const {
+ if (diffuse_texture.is_valid()) {
+ return diffuse_texture->get_width();
+ } else {
+ return 1;
+ }
+}
+int CanvasTexture::get_height() const {
+ if (diffuse_texture.is_valid()) {
+ return diffuse_texture->get_height();
+ } else {
+ return 1;
+ }
+}
+
+bool CanvasTexture::is_pixel_opaque(int p_x, int p_y) const {
+ if (diffuse_texture.is_valid()) {
+ return diffuse_texture->is_pixel_opaque(p_x, p_y);
+ } else {
+ return false;
+ }
+}
+
+bool CanvasTexture::has_alpha() const {
+ if (diffuse_texture.is_valid()) {
+ return diffuse_texture->has_alpha();
+ } else {
+ return false;
+ }
+}
+
+Ref<Image> CanvasTexture::get_image() const {
+ if (diffuse_texture.is_valid()) {
+ return diffuse_texture->get_image();
+ } else {
+ return Ref<Image>();
+ }
+}
+
+RID CanvasTexture::get_rid() const {
+ return canvas_texture;
+}
+
+void CanvasTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_diffuse_texture", "texture"), &CanvasTexture::set_diffuse_texture);
+ ClassDB::bind_method(D_METHOD("get_diffuse_texture"), &CanvasTexture::get_diffuse_texture);
+
+ ClassDB::bind_method(D_METHOD("set_normal_texture", "texture"), &CanvasTexture::set_normal_texture);
+ ClassDB::bind_method(D_METHOD("get_normal_texture"), &CanvasTexture::get_normal_texture);
+
+ ClassDB::bind_method(D_METHOD("set_specular_texture", "texture"), &CanvasTexture::set_specular_texture);
+ ClassDB::bind_method(D_METHOD("get_specular_texture"), &CanvasTexture::get_specular_texture);
+
+ ClassDB::bind_method(D_METHOD("set_specular_color", "color"), &CanvasTexture::set_specular_color);
+ ClassDB::bind_method(D_METHOD("get_specular_color"), &CanvasTexture::get_specular_color);
+
+ ClassDB::bind_method(D_METHOD("set_specular_shininess", "shininess"), &CanvasTexture::set_specular_shininess);
+ ClassDB::bind_method(D_METHOD("get_specular_shininess"), &CanvasTexture::get_specular_shininess);
+
+ ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &CanvasTexture::set_texture_filter);
+ ClassDB::bind_method(D_METHOD("get_texture_filter"), &CanvasTexture::get_texture_filter);
+
+ ClassDB::bind_method(D_METHOD("set_texture_repeat", "repeat"), &CanvasTexture::set_texture_repeat);
+ ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasTexture::get_texture_repeat);
+
+ ADD_GROUP("Diffuse", "diffuse_");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "diffuse_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_diffuse_texture", "get_diffuse_texture");
+ ADD_GROUP("Normalmap", "normal_");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_texture", "get_normal_texture");
+ ADD_GROUP("Specular", "specular_");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_texture", "get_specular_texture");
+ 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,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");
+}
+
+CanvasTexture::CanvasTexture() {
+ canvas_texture = RS::get_singleton()->canvas_texture_create();
+}
+CanvasTexture::~CanvasTexture() {
+ RS::get_singleton()->free(canvas_texture);
+}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index dc17c5283b..01ed47d4dc 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,136 +33,17 @@
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
-#include "scene/resources/material.h"
-#include "scene/resources/multimesh.h"
-#include "scene/resources/shader.h"
-#include "scene/resources/texture.h"
+#include "scene/resources/canvas_item_material.h"
+#include "servers/text_server.h"
class CanvasLayer;
-class Viewport;
class Font;
-
+class MultiMesh;
class StyleBox;
-
-class CanvasItemMaterial : public Material {
-
- GDCLASS(CanvasItemMaterial, Material);
-
-public:
- enum BlendMode {
- BLEND_MODE_MIX,
- BLEND_MODE_ADD,
- BLEND_MODE_SUB,
- BLEND_MODE_MUL,
- BLEND_MODE_PREMULT_ALPHA,
- BLEND_MODE_DISABLED
- };
-
- enum LightMode {
- LIGHT_MODE_NORMAL,
- LIGHT_MODE_UNSHADED,
- LIGHT_MODE_LIGHT_ONLY
- };
-
-private:
- union MaterialKey {
-
- struct {
- uint32_t blend_mode : 4;
- uint32_t light_mode : 4;
- uint32_t particles_animation : 1;
- uint32_t invalid_key : 1;
- };
-
- uint32_t key;
-
- bool operator<(const MaterialKey &p_key) const {
- return key < p_key.key;
- }
- };
-
- struct ShaderNames {
- StringName particles_anim_h_frames;
- StringName particles_anim_v_frames;
- StringName particles_anim_loop;
- };
-
- static ShaderNames *shader_names;
-
- struct ShaderData {
- RID shader;
- int users;
- };
-
- static Map<MaterialKey, ShaderData> shader_map;
-
- MaterialKey current_key;
-
- _FORCE_INLINE_ MaterialKey _compute_key() const {
-
- MaterialKey mk;
- mk.key = 0;
- mk.blend_mode = blend_mode;
- mk.light_mode = light_mode;
- mk.particles_animation = particles_animation;
- return mk;
- }
-
- static Mutex material_mutex;
- static SelfList<CanvasItemMaterial>::List *dirty_materials;
- SelfList<CanvasItemMaterial> element;
-
- void _update_shader();
- _FORCE_INLINE_ void _queue_shader_change();
- _FORCE_INLINE_ bool _is_shader_dirty() const;
-
- BlendMode blend_mode;
- LightMode light_mode;
- bool particles_animation;
-
- int particles_anim_h_frames;
- int particles_anim_v_frames;
- bool particles_anim_loop;
-
-protected:
- static void _bind_methods();
- void _validate_property(PropertyInfo &property) const;
-
-public:
- void set_blend_mode(BlendMode p_blend_mode);
- BlendMode get_blend_mode() const;
-
- void set_light_mode(LightMode p_light_mode);
- LightMode get_light_mode() const;
-
- void set_particles_animation(bool p_particles_anim);
- bool get_particles_animation() const;
-
- void set_particles_anim_h_frames(int p_frames);
- int get_particles_anim_h_frames() const;
- void set_particles_anim_v_frames(int p_frames);
- int get_particles_anim_v_frames() const;
-
- void set_particles_anim_loop(bool p_loop);
- bool get_particles_anim_loop() const;
-
- static void init_shaders();
- static void finish_shaders();
- static void flush_changes();
-
- RID get_shader_rid() const;
-
- virtual Shader::Mode get_shader_mode() const;
-
- CanvasItemMaterial();
- virtual ~CanvasItemMaterial();
-};
-
-VARIANT_ENUM_CAST(CanvasItemMaterial::BlendMode)
-VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode)
+class Window;
+class World2D;
class CanvasItem : public Node {
-
GDCLASS(CanvasItem, Node);
public:
@@ -189,42 +70,42 @@ private:
mutable SelfList<Node> xform_change;
RID canvas_item;
- String group;
+ StringName group;
- CanvasLayer *canvas_layer;
+ CanvasLayer *canvas_layer = nullptr;
- Color modulate;
- Color self_modulate;
+ Color modulate = Color(1, 1, 1, 1);
+ Color self_modulate = Color(1, 1, 1, 1);
List<CanvasItem *> children_items;
- List<CanvasItem *>::Element *C;
-
- int light_mask;
-
- Window *window;
- bool first_draw;
- bool visible;
- bool pending_update;
- bool toplevel;
- bool drawing;
- bool block_transform_notify;
- bool behind;
- bool use_parent_material;
- bool notify_local_transform;
- bool notify_transform;
-
- RS::CanvasItemTextureFilter texture_filter_cache;
- RS::CanvasItemTextureRepeat texture_repeat_cache;
-
- TextureFilter texture_filter;
- TextureRepeat texture_repeat;
+ List<CanvasItem *>::Element *C = nullptr;
+
+ int light_mask = 1;
+
+ Window *window = nullptr;
+ bool first_draw = false;
+ bool visible = true;
+ bool clip_children = false;
+ bool pending_update = false;
+ bool top_level = false;
+ bool drawing = false;
+ bool block_transform_notify = false;
+ bool behind = false;
+ bool use_parent_material = false;
+ bool notify_local_transform = false;
+ bool notify_transform = false;
+
+ RS::CanvasItemTextureFilter texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
+ RS::CanvasItemTextureRepeat texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
+ TextureFilter texture_filter = TEXTURE_FILTER_PARENT_NODE;
+ TextureRepeat texture_repeat = TEXTURE_REPEAT_PARENT_NODE;
Ref<Material> material;
mutable Transform2D global_transform;
- mutable bool global_invalid;
+ mutable bool global_invalid = true;
- void _toplevel_raise_self();
+ void _top_level_raise_self();
void _propagate_visibility_changed(bool p_visible);
@@ -247,9 +128,13 @@ private:
protected:
_FORCE_INLINE_ void _notify_transform() {
- if (!is_inside_tree()) return;
+ if (!is_inside_tree()) {
+ return;
+ }
_notify_transform(this);
- if (!block_transform_notify && notify_local_transform) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
+ if (!block_transform_notify && notify_local_transform) {
+ notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
+ }
}
void item_rect_changed(bool p_size_changed = true);
@@ -257,6 +142,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ GDVIRTUAL0(_draw)
public:
enum {
NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique
@@ -275,7 +161,7 @@ public:
virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
// Save and restore a CanvasItem state
- virtual void _edit_set_state(const Dictionary &p_state){};
+ virtual void _edit_set_state(const Dictionary &p_state) {}
virtual Dictionary _edit_get_state() const { return Dictionary(); };
// Used to move the node
@@ -288,18 +174,18 @@ 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()
- virtual void _edit_set_rect(const Rect2 &p_rect){};
+ virtual void _edit_set_rect(const Rect2 &p_rect) {}
virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); };
virtual Size2 _edit_get_minimum_size() const { return Size2(-1, -1); }; // LOOKS WEIRD
// Used to set a pivot
virtual bool _edit_use_pivot() const { return false; };
- virtual void _edit_set_pivot(const Point2 &p_pivot){};
+ virtual void _edit_set_pivot(const Point2 &p_pivot) {}
virtual Point2 _edit_get_pivot() const { return Point2(); };
virtual Transform2D _edit_get_transform() const;
@@ -315,6 +201,9 @@ public:
void update();
+ void set_clip_children(bool p_enabled);
+ bool is_clipping_children() const;
+
virtual void set_light_mask(int p_light_mask);
int get_light_mask() const;
@@ -326,37 +215,41 @@ 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);
- void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
- 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);
- 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_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), bool p_clip_uv = false, TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ 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_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0);
void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
- void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), float p_width = 1, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- 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>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- 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>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ 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, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
- float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));
+ 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, const Size2 &p_scale);
+ 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();
/* RECT / TRANSFORM */
- void set_as_toplevel(bool p_toplevel);
- bool is_set_as_toplevel() const;
+ void set_as_top_level(bool p_top_level);
+ bool is_set_as_top_level() const;
void set_draw_behind_parent(bool p_enable);
bool is_draw_behind_parent_enabled() const;
@@ -369,7 +262,7 @@ public:
virtual Transform2D get_global_transform_with_canvas() const;
virtual Transform2D get_screen_transform() const;
- CanvasItem *get_toplevel() const;
+ CanvasItem *get_top_level() const;
_FORCE_INLINE_ RID get_canvas_item() const {
return canvas_item;
}
@@ -405,10 +298,10 @@ public:
void force_update_transform();
- void set_texture_filter(TextureFilter p_texture_filter);
+ virtual void set_texture_filter(TextureFilter p_texture_filter);
TextureFilter get_texture_filter() const;
- void set_texture_repeat(TextureRepeat p_texture_repeat);
+ virtual void set_texture_repeat(TextureRepeat p_texture_repeat);
TextureRepeat get_texture_repeat() const;
// Used by control nodes to retrieve the parent's anchorable area
@@ -423,4 +316,58 @@ public:
VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
+class CanvasTexture : public Texture2D {
+ GDCLASS(CanvasTexture, Texture2D);
+ OBJ_SAVE_TYPE(Texture2D); // Saves derived classes with common type so they can be interchanged.
+
+ Ref<Texture2D> diffuse_texture;
+ Ref<Texture2D> normal_texture;
+ Ref<Texture2D> specular_texture;
+ Color specular = Color(1, 1, 1, 1);
+ real_t shininess = 1.0;
+
+ RID canvas_texture;
+
+ CanvasItem::TextureFilter texture_filter = CanvasItem::TEXTURE_FILTER_PARENT_NODE;
+ CanvasItem::TextureRepeat texture_repeat = CanvasItem::TEXTURE_REPEAT_PARENT_NODE;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_diffuse_texture(const Ref<Texture2D> &p_diffuse);
+ Ref<Texture2D> get_diffuse_texture() const;
+
+ void set_normal_texture(const Ref<Texture2D> &p_normal);
+ Ref<Texture2D> get_normal_texture() const;
+
+ void set_specular_texture(const Ref<Texture2D> &p_specular);
+ Ref<Texture2D> get_specular_texture() const;
+
+ void set_specular_color(const Color &p_color);
+ Color get_specular_color() 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;
+
+ void set_texture_repeat(CanvasItem::TextureRepeat p_repeat);
+ CanvasItem::TextureRepeat get_texture_repeat() const;
+
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+
+ virtual bool is_pixel_opaque(int p_x, int p_y) const override;
+ virtual bool has_alpha() const override;
+
+ virtual Ref<Image> get_image() const override;
+
+ virtual RID get_rid() const override;
+
+ CanvasTexture();
+ ~CanvasTexture();
+};
+
#endif // CANVAS_ITEM_H
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index c1caa943e3..4540e42b4c 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,40 +32,37 @@
#include "viewport.h"
void CanvasLayer::set_layer(int p_xform) {
-
layer = p_xform;
- if (viewport.is_valid())
+ if (viewport.is_valid()) {
RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
+ }
}
int CanvasLayer::get_layer() const {
-
return layer;
}
void CanvasLayer::set_transform(const Transform2D &p_xform) {
-
transform = p_xform;
locrotscale_dirty = true;
- if (viewport.is_valid())
+ if (viewport.is_valid()) {
RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ }
}
Transform2D CanvasLayer::get_transform() const {
-
return transform;
}
void CanvasLayer::_update_xform() {
-
transform.set_rotation_and_scale(rot, scale);
transform.set_origin(ofs);
- if (viewport.is_valid())
+ if (viewport.is_valid()) {
RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ }
}
void CanvasLayer::_update_locrotscale() {
-
ofs = transform.elements[2];
rot = transform.get_rotation();
scale = transform.get_scale();
@@ -73,74 +70,60 @@ void CanvasLayer::_update_locrotscale() {
}
void CanvasLayer::set_offset(const Vector2 &p_offset) {
-
- if (locrotscale_dirty)
+ if (locrotscale_dirty) {
_update_locrotscale();
+ }
ofs = p_offset;
_update_xform();
}
Vector2 CanvasLayer::get_offset() const {
-
- if (locrotscale_dirty)
+ if (locrotscale_dirty) {
const_cast<CanvasLayer *>(this)->_update_locrotscale();
+ }
return ofs;
}
void CanvasLayer::set_rotation(real_t p_radians) {
-
- if (locrotscale_dirty)
+ if (locrotscale_dirty) {
_update_locrotscale();
+ }
rot = p_radians;
_update_xform();
}
real_t CanvasLayer::get_rotation() const {
-
- if (locrotscale_dirty)
+ if (locrotscale_dirty) {
const_cast<CanvasLayer *>(this)->_update_locrotscale();
+ }
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)
+ if (locrotscale_dirty) {
_update_locrotscale();
+ }
scale = p_scale;
_update_xform();
}
Vector2 CanvasLayer::get_scale() const {
-
- if (locrotscale_dirty)
+ if (locrotscale_dirty) {
const_cast<CanvasLayer *>(this)->_update_locrotscale();
+ }
return scale;
}
void CanvasLayer::_notification(int p_what) {
-
switch (p_what) {
-
case NOTIFICATION_ENTER_TREE: {
-
if (custom_viewport && ObjectDB::get_instance(custom_viewport_id)) {
-
vp = custom_viewport;
} else {
vp = Node::get_viewport();
@@ -157,7 +140,6 @@ void CanvasLayer::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
-
vp->_canvas_layer_remove(this);
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
@@ -165,25 +147,24 @@ void CanvasLayer::_notification(int p_what) {
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
-
- if (is_inside_tree())
+ if (is_inside_tree()) {
RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
+ }
} break;
}
}
Size2 CanvasLayer::get_viewport_size() const {
-
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
return Size2(1, 1);
+ }
Rect2 r = vp->get_visible_rect();
return r.size;
}
RID CanvasLayer::get_viewport() const {
-
return viewport;
}
@@ -204,11 +185,11 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
}
if (is_inside_tree()) {
-
- if (custom_viewport)
+ if (custom_viewport) {
vp = custom_viewport;
- else
+ } else {
vp = Node::get_viewport();
+ }
vp->_canvas_layer_add(this);
viewport = vp->get_viewport_rid();
@@ -220,7 +201,6 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
}
Node *CanvasLayer::get_custom_viewport() const {
-
return custom_viewport;
}
@@ -229,12 +209,10 @@ void CanvasLayer::reset_sort_index() {
}
int CanvasLayer::get_sort_index() {
-
return sort_index++;
}
RID CanvasLayer::get_canvas() const {
-
return canvas;
}
@@ -245,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 {
@@ -261,7 +240,6 @@ float CanvasLayer::get_follow_viewport_scale() const {
}
void CanvasLayer::_update_follow_viewport(bool p_force_exit) {
-
if (!is_inside_tree()) {
return;
}
@@ -272,8 +250,13 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) {
}
}
-void CanvasLayer::_bind_methods() {
+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);
@@ -286,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);
@@ -307,33 +287,20 @@ 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");
}
CanvasLayer::CanvasLayer() {
-
- vp = nullptr;
- scale = Vector2(1, 1);
- rot = 0;
- locrotscale_dirty = false;
- layer = 1;
canvas = RS::get_singleton()->canvas_create();
- custom_viewport = nullptr;
-
- sort_index = 0;
- follow_viewport = false;
- follow_viewport_scale = 1.0;
}
CanvasLayer::~CanvasLayer() {
-
RS::get_singleton()->free(canvas);
}
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index 91ddbca3b9..9d8e0c203d 100644
--- a/scene/main/canvas_layer.h
+++ b/scene/main/canvas_layer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,31 +32,29 @@
#define CANVAS_LAYER_H
#include "scene/main/node.h"
-#include "scene/resources/world_2d.h"
class Viewport;
class CanvasLayer : public Node {
-
GDCLASS(CanvasLayer, Node);
- bool locrotscale_dirty;
+ bool locrotscale_dirty = false;
Vector2 ofs;
- Size2 scale;
- real_t rot;
- int layer;
+ Size2 scale = Vector2(1, 1);
+ real_t rot = 0.0;
+ int layer = 1;
Transform2D transform;
RID canvas;
ObjectID custom_viewport_id; // to check validity
- Viewport *custom_viewport;
+ Viewport *custom_viewport = nullptr;
RID viewport;
- Viewport *vp;
+ Viewport *vp = nullptr;
- int sort_index;
+ int sort_index = 0;
- bool follow_viewport;
- float follow_viewport_scale;
+ bool follow_viewport = false;
+ float follow_viewport_scale = 1.0;
void _update_xform();
void _update_locrotscale();
@@ -65,6 +63,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);
@@ -79,9 +78,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 dc0da015ac..f24d880045 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,63 +29,89 @@
/*************************************************************************/
#include "http_request.h"
+#include "core/io/compression.h"
+#include "scene/main/timer.h"
void HTTPRequest::_redirect_request(const String &p_new_url) {
}
Error HTTPRequest::_request() {
-
return client->connect_to_host(url, port, use_ssl, validate_ssl);
}
Error HTTPRequest::_parse_url(const String &p_url) {
-
- url = p_url;
use_ssl = false;
-
request_string = "";
port = 80;
request_sent = false;
got_response = false;
body_len = -1;
body.resize(0);
- downloaded = 0;
+ 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 + ".");
}
+ if (port == 0) {
+ port = use_ssl ? 443 : 80;
+ }
+ if (request_string.is_empty()) {
+ request_string = "/";
+ }
+ return OK;
+}
- ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short: " + url + ".");
-
- int slash_pos = url.find("/");
+bool HTTPRequest::has_header(const PackedStringArray &p_headers, const String &p_header_name) {
+ bool exists = false;
- if (slash_pos != -1) {
- request_string = url.substr(slash_pos, url.length());
- url = url.substr(0, slash_pos);
- } else {
- request_string = "/";
+ String lower_case_header_name = p_header_name.to_lower();
+ for (int i = 0; i < p_headers.size() && !exists; i++) {
+ String sanitized = p_headers[i].strip_edges().to_lower();
+ if (sanitized.begins_with(lower_case_header_name)) {
+ exists = true;
+ }
}
- 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);
+ return exists;
+}
+
+String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const String &p_header_name) {
+ String value = "";
+
+ String lowwer_case_header_name = p_header_name.to_lower();
+ for (int i = 0; i < p_headers.size(); i++) {
+ if (p_headers[i].find(":", 0) >= 0) {
+ Vector<String> parts = p_headers[i].split(":", false, 1);
+ if (parts[0].strip_edges().to_lower() == lowwer_case_header_name) {
+ value = parts[1].strip_edges();
+ break;
+ }
+ }
}
- return OK;
+ return value;
}
Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const String &p_request_data) {
+ // Copy the string into a raw buffer
+ Vector<uint8_t> raw_data;
+
+ CharString charstr = p_request_data.utf8();
+ size_t len = charstr.length();
+ raw_data.resize(len);
+ uint8_t *w = raw_data.ptrw();
+ memcpy(w, charstr.ptr(), len);
+
+ return request_raw(p_url, p_custom_headers, p_ssl_validate_domain, p_method, raw_data);
+}
+Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) {
ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(requesting, ERR_BUSY, "HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one.");
@@ -97,28 +123,35 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
method = p_method;
Error err = _parse_url(p_url);
- if (err)
+ if (err) {
return err;
+ }
validate_ssl = p_ssl_validate_domain;
headers = p_custom_headers;
- request_data = p_request_data;
+ if (accept_gzip) {
+ // If the user has specified a different Accept-Encoding, don't overwrite it
+ if (!has_header(headers, "Accept-Encoding")) {
+ headers.push_back("Accept-Encoding: gzip, deflate");
+ }
+ }
- requesting = true;
+ request_data = p_request_data_raw;
- if (use_threads) {
+ requesting = true;
- thread_done = false;
- thread_request_quit = false;
+ if (use_threads.is_set()) {
+ thread_done.clear();
+ thread_request_quit.clear();
client->set_blocking_mode(true);
- thread = Thread::create(_thread_func, this);
+ thread.start(_thread_func, this);
} else {
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;
}
@@ -129,40 +162,37 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
}
void HTTPRequest::_thread_func(void *p_userdata) {
-
HTTPRequest *hr = (HTTPRequest *)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) {
-
+ while (!hr->thread_request_quit.is_set()) {
bool exit = hr->_update_connection();
- if (exit)
+ if (exit) {
break;
+ }
OS::get_singleton()->delay_usec(1);
}
}
- hr->thread_done = true;
+ hr->thread_done.set();
}
void HTTPRequest::cancel_request() {
-
timer->stop();
- if (!requesting)
+ if (!requesting) {
return;
+ }
- if (!use_threads) {
+ if (!use_threads.is_set()) {
set_process_internal(false);
} else {
- thread_request_quit = true;
- Thread::wait_to_finish(thread);
- memdelete(thread);
- thread = nullptr;
+ thread_request_quit.set();
+ thread.wait_to_finish();
}
if (file) {
@@ -178,9 +208,8 @@ 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;
}
@@ -190,26 +219,25 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
List<String> rheaders;
client->get_response_headers(&rheaders);
response_headers.resize(0);
- downloaded = 0;
- for (List<String>::Element *E = rheaders.front(); E; E = E->next()) {
- response_headers.push_back(E->get());
+ downloaded.set(0);
+ for (const String &E : rheaders) {
+ response_headers.push_back(E);
}
if (response_code == 301 || response_code == 302) {
// Handle redirect
if (max_redirects >= 0 && redirections >= max_redirects) {
-
- call_deferred("_request_done", RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray());
*ret_value = true;
return true;
}
String new_request;
- for (List<String>::Element *E = rheaders.front(); E; E = E->next()) {
- if (E->get().findn("Location: ") != -1) {
- new_request = E->get().substr(9, E->get().length()).strip_edges();
+ for (const String &E : rheaders) {
+ if (E.findn("Location: ") != -1) {
+ new_request = E.substr(9, E.length()).strip_edges();
}
}
@@ -231,7 +259,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
got_response = false;
body_len = -1;
body.resize(0);
- downloaded = 0;
+ downloaded.set(0);
redirections = new_redirs;
*ret_value = false;
return true;
@@ -243,10 +271,9 @@ 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: {
@@ -255,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;
@@ -265,42 +292,40 @@ 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;
case HTTPClient::STATUS_CONNECTED: {
-
if (request_sent) {
-
if (!got_response) {
-
// No body
bool ret_value;
- if (_handle_response(&ret_value))
+ if (_handle_response(&ret_value)) {
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(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;
}
@@ -315,17 +340,15 @@ bool HTTPRequest::_update_connection() {
} break; // Request in progress
case HTTPClient::STATUS_BODY: {
-
if (!got_response) {
-
bool ret_value;
- if (_handle_response(&ret_value))
+ if (_handle_response(&ret_value)) {
return ret_value;
+ }
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;
}
@@ -334,61 +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 += 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 > body_size_limit) {
- call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
+ if (body_size_limit >= 0 && downloaded.get() > body_size_limit) {
+ call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
return true;
}
if (body_len >= 0) {
-
- if (downloaded == body_len) {
- call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
+ if (downloaded.get() == body_len) {
+ 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;
}
@@ -396,21 +423,56 @@ bool HTTPRequest::_update_connection() {
ERR_FAIL_V(false);
}
-void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) {
-
+void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) {
cancel_request();
- emit_signal("request_completed", p_status, p_code, headers, p_data);
+
+ // Determine if the request body is compressed
+ bool is_compressed;
+ String content_encoding = get_header_value(p_headers, "Content-Encoding").to_lower();
+ Compression::Mode mode;
+ if (content_encoding == "gzip") {
+ mode = Compression::Mode::MODE_GZIP;
+ is_compressed = true;
+ } else if (content_encoding == "deflate") {
+ mode = Compression::Mode::MODE_DEFLATE;
+ is_compressed = true;
+ } else {
+ is_compressed = false;
+ }
+
+ const PackedByteArray *data = nullptr;
+
+ if (accept_gzip && is_compressed && p_data.size() > 0) {
+ // Decompress request body
+ PackedByteArray *decompressed = memnew(PackedByteArray);
+ int result = Compression::decompress_dynamic(decompressed, body_size_limit, p_data.ptr(), p_data.size(), mode);
+ if (result == OK) {
+ data = decompressed;
+ } else if (result == -5) {
+ WARN_PRINT("Decompressed size of HTTP response body exceeded body_size_limit");
+ p_status = RESULT_BODY_SIZE_LIMIT_EXCEEDED;
+ // Just return the raw data if we failed to decompress it
+ data = &p_data;
+ } else {
+ WARN_PRINT("Failed to decompress HTTP response body");
+ p_status = RESULT_BODY_DECOMPRESS_FAILED;
+ // Just return the raw data if we failed to decompress it
+ data = &p_data;
+ }
+ } else {
+ data = &p_data;
+ }
+
+ emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, *data);
}
void HTTPRequest::_notification(int p_what) {
-
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
- if (use_threads)
+ if (use_threads.is_set()) {
return;
+ }
bool done = _update_connection();
if (done) {
-
set_process_internal(false);
// cancel_request(); called from _request done now
}
@@ -424,42 +486,43 @@ void HTTPRequest::_notification(int p_what) {
}
void HTTPRequest::set_use_threads(bool p_use) {
-
ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED);
- use_threads = p_use;
+ use_threads.set_to(p_use);
}
bool HTTPRequest::is_using_threads() const {
+ return use_threads.is_set();
+}
- return use_threads;
+void HTTPRequest::set_accept_gzip(bool p_gzip) {
+ accept_gzip = p_gzip;
}
-void HTTPRequest::set_body_size_limit(int p_bytes) {
+bool HTTPRequest::is_accepting_gzip() const {
+ return accept_gzip;
+}
+void HTTPRequest::set_body_size_limit(int p_bytes) {
ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED);
body_size_limit = p_bytes;
}
int HTTPRequest::get_body_size_limit() const {
-
return body_size_limit;
}
void HTTPRequest::set_download_file(const String &p_file) {
-
ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED);
download_to_file = p_file;
}
String HTTPRequest::get_download_file() const {
-
return download_to_file;
}
void HTTPRequest::set_download_chunk_size(int p_chunk_size) {
-
ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED);
client->set_read_chunk_size(p_chunk_size);
@@ -474,43 +537,38 @@ HTTPClient::Status HTTPRequest::get_http_client_status() const {
}
void HTTPRequest::set_max_redirects(int p_max) {
-
max_redirects = p_max;
}
int HTTPRequest::get_max_redirects() const {
-
return max_redirects;
}
int HTTPRequest::get_downloaded_bytes() const {
-
- return downloaded;
+ return downloaded.get();
}
+
int HTTPRequest::get_body_size() const {
return body_len;
}
void HTTPRequest::set_timeout(int p_timeout) {
-
ERR_FAIL_COND(p_timeout < 0);
timeout = p_timeout;
}
int HTTPRequest::get_timeout() {
-
return 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() {
-
ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "ssl_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String()));
+ ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "ssl_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray()));
ClassDB::bind_method(D_METHOD("cancel_request"), &HTTPRequest::cancel_request);
ClassDB::bind_method(D_METHOD("get_http_client_status"), &HTTPRequest::get_http_client_status);
@@ -518,6 +576,9 @@ void HTTPRequest::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_threads", "enable"), &HTTPRequest::set_use_threads);
ClassDB::bind_method(D_METHOD("is_using_threads"), &HTTPRequest::is_using_threads);
+ ClassDB::bind_method(D_METHOD("set_accept_gzip", "enable"), &HTTPRequest::set_accept_gzip);
+ ClassDB::bind_method(D_METHOD("is_accepting_gzip"), &HTTPRequest::is_accepting_gzip);
+
ClassDB::bind_method(D_METHOD("set_body_size_limit", "bytes"), &HTTPRequest::set_body_size_limit);
ClassDB::bind_method(D_METHOD("get_body_size_limit"), &HTTPRequest::get_body_size_limit);
@@ -542,6 +603,7 @@ void HTTPRequest::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "download_file", PROPERTY_HINT_FILE), "set_download_file", "get_download_file");
ADD_PROPERTY(PropertyInfo(Variant::INT, "download_chunk_size", PROPERTY_HINT_RANGE, "256,16777216"), "set_download_chunk_size", "get_download_chunk_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_threads"), "set_use_threads", "is_using_threads");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "accept_gzip"), "set_accept_gzip", "is_accepting_gzip");
ADD_PROPERTY(PropertyInfo(Variant::INT, "body_size_limit", PROPERTY_HINT_RANGE, "-1,2000000000"), "set_body_size_limit", "get_body_size_limit");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,64"), "set_max_redirects", "get_max_redirects");
ADD_PROPERTY(PropertyInfo(Variant::INT, "timeout", PROPERTY_HINT_RANGE, "0,86400"), "set_timeout", "get_timeout");
@@ -557,6 +619,7 @@ void HTTPRequest::_bind_methods() {
BIND_ENUM_CONSTANT(RESULT_SSL_HANDSHAKE_ERROR);
BIND_ENUM_CONSTANT(RESULT_NO_RESPONSE);
BIND_ENUM_CONSTANT(RESULT_BODY_SIZE_LIMIT_EXCEEDED);
+ BIND_ENUM_CONSTANT(RESULT_BODY_DECOMPRESS_FAILED);
BIND_ENUM_CONSTANT(RESULT_REQUEST_FAILED);
BIND_ENUM_CONSTANT(RESULT_DOWNLOAD_FILE_CANT_OPEN);
BIND_ENUM_CONSTANT(RESULT_DOWNLOAD_FILE_WRITE_ERROR);
@@ -565,34 +628,15 @@ void HTTPRequest::_bind_methods() {
}
HTTPRequest::HTTPRequest() {
-
- thread = nullptr;
-
- port = 80;
- redirections = 0;
- max_redirects = 8;
- body_len = -1;
- got_response = false;
- validate_ssl = false;
- use_ssl = false;
- response_code = 0;
- request_sent = false;
- requesting = false;
- client.instance();
- use_threads = false;
- thread_done = false;
- downloaded = 0;
- body_size_limit = -1;
- file = nullptr;
-
+ client = Ref<HTTPClient>(HTTPClient::create());
timer = memnew(Timer);
timer->set_one_shot(true);
timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout));
add_child(timer);
- timeout = 0;
}
HTTPRequest::~HTTPRequest() {
- if (file)
+ if (file) {
memdelete(file);
+ }
}
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index a3d95cd652..673cf3a740 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,13 +32,13 @@
#define HTTPREQUEST_H
#include "core/io/http_client.h"
-#include "core/os/file_access.h"
#include "core/os/thread.h"
-#include "node.h"
-#include "scene/main/timer.h"
+#include "core/templates/safe_refcount.h"
+#include "scene/main/node.h"
-class HTTPRequest : public Node {
+class Timer;
+class HTTPRequest : public Node {
GDCLASS(HTTPRequest, Node);
public:
@@ -51,6 +51,7 @@ public:
RESULT_SSL_HANDSHAKE_ERROR,
RESULT_NO_RESPONSE,
RESULT_BODY_SIZE_LIMIT_EXCEEDED,
+ RESULT_BODY_DECOMPRESS_FAILED,
RESULT_REQUEST_FAILED,
RESULT_DOWNLOAD_FILE_CANT_OPEN,
RESULT_DOWNLOAD_FILE_WRITE_ERROR,
@@ -60,41 +61,42 @@ public:
};
private:
- bool requesting;
+ bool requesting = false;
String request_string;
String url;
- int port;
+ int port = 80;
Vector<String> headers;
- bool validate_ssl;
- bool use_ssl;
+ bool validate_ssl = false;
+ bool use_ssl = false;
HTTPClient::Method method;
- String request_data;
+ Vector<uint8_t> request_data;
- bool request_sent;
+ bool request_sent = false;
Ref<HTTPClient> client;
PackedByteArray body;
- volatile bool use_threads;
+ SafeFlag use_threads;
+ bool accept_gzip = true;
- bool got_response;
- int response_code;
+ bool got_response = false;
+ int response_code = 0;
Vector<String> response_headers;
String download_to_file;
- FileAccess *file;
+ FileAccess *file = nullptr;
- int body_len;
- volatile int downloaded;
- int body_size_limit;
+ int body_len = -1;
+ SafeNumeric<int> downloaded;
+ int body_size_limit = -1;
- int redirections;
+ int redirections = 0;
bool _update_connection();
- int max_redirects;
+ int max_redirects = 8;
- int timeout;
+ int timeout = 0;
void _redirect_request(const String &p_new_url);
@@ -103,12 +105,15 @@ private:
Error _parse_url(const String &p_url);
Error _request();
- volatile bool thread_done;
- volatile bool thread_request_quit;
+ bool has_header(const PackedStringArray &p_headers, const String &p_header_name);
+ String get_header_value(const PackedStringArray &p_headers, const String &header_name);
- Thread *thread;
+ SafeFlag thread_done;
+ SafeFlag thread_request_quit;
- void _request_done(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
+ Thread thread;
+
+ void _request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data);
static void _thread_func(void *p_userdata);
protected:
@@ -117,12 +122,16 @@ protected:
public:
Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request
+ Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request
void cancel_request();
HTTPClient::Status get_http_client_status() const;
void set_use_threads(bool p_use);
bool is_using_threads() const;
+ void set_accept_gzip(bool p_gzip);
+ bool is_accepting_gzip() const;
+
void set_download_file(const String &p_file);
String get_download_file() const;
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index 062b221c84..b5ba1899ec 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,6 @@
#include "scene/resources/packed_scene.h"
bool InstancePlaceholder::_set(const StringName &p_name, const Variant &p_value) {
-
PropSet ps;
ps.name = p_name;
ps.value = p_value;
@@ -43,10 +42,9 @@ bool InstancePlaceholder::_set(const StringName &p_name, const Variant &p_value)
}
bool InstancePlaceholder::_get(const StringName &p_name, Variant &r_ret) const {
-
- for (const List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) {
- if (E->get().name == p_name) {
- r_ret = E->get().value;
+ for (const PropSet &E : stored_values) {
+ if (E.name == p_name) {
+ r_ret = E.value;
return true;
}
}
@@ -54,11 +52,10 @@ bool InstancePlaceholder::_get(const StringName &p_name, Variant &r_ret) const {
}
void InstancePlaceholder::_get_property_list(List<PropertyInfo> *p_list) const {
-
- for (const List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) {
+ for (const PropSet &E : stored_values) {
PropertyInfo pi;
- pi.name = E->get().name;
- pi.type = E->get().value.get_type();
+ pi.name = E.name;
+ pi.type = E.value.get_type();
pi.usage = PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
@@ -66,39 +63,40 @@ void InstancePlaceholder::_get_property_list(List<PropertyInfo> *p_list) const {
}
void InstancePlaceholder::set_instance_path(const String &p_name) {
-
path = p_name;
}
String InstancePlaceholder::get_instance_path() const {
-
return path;
}
Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene> &p_custom_scene) {
-
ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
Node *base = get_parent();
- if (!base)
+ if (!base) {
return nullptr;
+ }
Ref<PackedScene> ps;
- if (p_custom_scene.is_valid())
+ if (p_custom_scene.is_valid()) {
ps = p_custom_scene;
- else
+ } else {
ps = ResourceLoader::load(path, "PackedScene");
+ }
- if (!ps.is_valid())
+ if (!ps.is_valid()) {
return nullptr;
- Node *scene = ps->instance();
- if (!scene)
+ }
+ Node *scene = ps->instantiate();
+ if (!scene) {
return nullptr;
+ }
scene->set_name(get_name());
int pos = get_index();
- for (List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) {
- scene->set(E->get().name, E->get().value);
+ for (const PropSet &E : stored_values) {
+ scene->set(E.name, E.value);
}
if (p_replace) {
@@ -113,24 +111,24 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene
}
Dictionary InstancePlaceholder::get_stored_values(bool p_with_order) {
-
Dictionary ret;
PackedStringArray order;
- for (List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) {
- ret[E->get().name] = E->get().value;
- if (p_with_order)
- order.push_back(E->get().name);
+ for (const PropSet &E : stored_values) {
+ ret[E.name] = E.value;
+ if (p_with_order) {
+ order.push_back(E.name);
+ }
};
- if (p_with_order)
+ if (p_with_order) {
ret[".order"] = order;
+ }
return ret;
};
void InstancePlaceholder::_bind_methods() {
-
ClassDB::bind_method(D_METHOD("get_stored_values", "with_order"), &InstancePlaceholder::get_stored_values, DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_instance", "replace", "custom_scene"), &InstancePlaceholder::create_instance, DEFVAL(false), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("get_instance_path"), &InstancePlaceholder::get_instance_path);
diff --git a/scene/main/instance_placeholder.h b/scene/main/instance_placeholder.h
index 9f7b84716d..fe20fc4760 100644
--- a/scene/main/instance_placeholder.h
+++ b/scene/main/instance_placeholder.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,7 +36,6 @@
class PackedScene;
class InstancePlaceholder : public Node {
-
GDCLASS(InstancePlaceholder, Node);
String path;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 50f3bf834f..05409b7bfe 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,9 +32,10 @@
#include "core/core_string_names.h"
#include "core/io/resource_loader.h"
-#include "core/message_queue.h"
-#include "core/print_string.h"
+#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"
@@ -46,53 +47,44 @@
#include <stdint.h>
-VARIANT_ENUM_CAST(Node::PauseMode);
+VARIANT_ENUM_CAST(Node::ProcessMode);
+VARIANT_ENUM_CAST(Node::InternalMode);
int Node::orphan_node_count = 0;
void Node::_notification(int p_notification) {
-
switch (p_notification) {
-
case NOTIFICATION_PROCESS: {
+ GDVIRTUAL_CALL(_process, get_process_delta_time());
- if (get_script_instance()) {
-
- Variant time = get_process_delta_time();
- const Variant *ptr[1] = { &time };
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_process, ptr, 1);
- }
} break;
case NOTIFICATION_PHYSICS_PROCESS: {
-
- if (get_script_instance()) {
-
- Variant time = get_physics_process_delta_time();
- const Variant *ptr[1] = { &time };
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_physics_process, ptr, 1);
- }
+ GDVIRTUAL_CALL(_physics_process, get_physics_process_delta_time());
} break;
case NOTIFICATION_ENTER_TREE: {
ERR_FAIL_COND(!get_viewport());
ERR_FAIL_COND(!get_tree());
- if (data.pause_mode == PAUSE_MODE_INHERIT) {
-
- if (data.parent)
- data.pause_owner = data.parent->data.pause_owner;
- else
- data.pause_owner = nullptr;
+ if (data.process_mode == PROCESS_MODE_INHERIT) {
+ if (data.parent) {
+ data.process_owner = data.parent->data.process_owner;
+ } else {
+ data.process_owner = nullptr;
+ }
} else {
- data.pause_owner = this;
+ data.process_owner = this;
}
- if (data.input)
+ if (data.input) {
add_to_group("_vp_input" + itos(get_viewport()->get_instance_id()));
- if (data.unhandled_input)
+ }
+ if (data.unhandled_input) {
add_to_group("_vp_unhandled_input" + itos(get_viewport()->get_instance_id()));
- if (data.unhandled_key_input)
+ }
+ if (data.unhandled_key_input) {
add_to_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id()));
+ }
get_tree()->node_count++;
orphan_node_count--;
@@ -105,51 +97,56 @@ void Node::_notification(int p_notification) {
get_tree()->node_count--;
orphan_node_count++;
- if (data.input)
+ if (data.input) {
remove_from_group("_vp_input" + itos(get_viewport()->get_instance_id()));
- if (data.unhandled_input)
+ }
+ if (data.unhandled_input) {
remove_from_group("_vp_unhandled_input" + itos(get_viewport()->get_instance_id()));
- if (data.unhandled_key_input)
+ }
+ if (data.unhandled_key_input) {
remove_from_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id()));
+ }
- data.pause_owner = nullptr;
+ data.process_owner = nullptr;
if (data.path_cache) {
memdelete(data.path_cache);
data.path_cache = nullptr;
}
+ if (data.filename.length()) {
+ get_multiplayer()->scene_enter_exit_notify(data.filename, this, false);
+ }
} break;
case NOTIFICATION_PATH_CHANGED: {
-
if (data.path_cache) {
memdelete(data.path_cache);
data.path_cache = nullptr;
}
} break;
case NOTIFICATION_READY: {
+ if (GDVIRTUAL_IS_OVERRIDDEN(_input)) {
+ set_process_input(true);
+ }
- if (get_script_instance()) {
-
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_input)) {
- set_process_input(true);
- }
-
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_unhandled_input)) {
- set_process_unhandled_input(true);
- }
+ if (GDVIRTUAL_IS_OVERRIDDEN(_unhandled_input)) {
+ set_process_unhandled_input(true);
+ }
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_unhandled_key_input)) {
- set_process_unhandled_key_input(true);
- }
+ if (GDVIRTUAL_IS_OVERRIDDEN(_unhandled_key_input)) {
+ set_process_unhandled_key_input(true);
+ }
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_process)) {
- set_process(true);
- }
+ if (GDVIRTUAL_IS_OVERRIDDEN(_process)) {
+ set_process(true);
+ }
+ if (GDVIRTUAL_IS_OVERRIDDEN(_physics_process)) {
+ set_physics_process(true);
+ }
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_physics_process)) {
- set_physics_process(true);
- }
+ GDVIRTUAL_CALL(_ready);
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, nullptr, 0);
+ if (data.filename.length()) {
+ ERR_FAIL_COND(!is_inside_tree());
+ get_multiplayer()->scene_enter_exit_notify(data.filename, this, true);
}
} break;
@@ -157,22 +154,18 @@ void Node::_notification(int p_notification) {
data.in_constructor = false;
} break;
case NOTIFICATION_PREDELETE: {
-
set_owner(nullptr);
while (data.owned.size()) {
-
data.owned.front()->get()->set_owner(nullptr);
}
if (data.parent) {
-
data.parent->remove_child(this);
}
// kill children as cleanly as possible
while (data.children.size()) {
-
Node *child = data.children[data.children.size() - 1]; //begin from the end because its faster and more consistent with creation
remove_child(child);
memdelete(child);
@@ -183,11 +176,9 @@ void Node::_notification(int p_notification) {
}
void Node::_propagate_ready() {
-
data.ready_notified = true;
data.blocked++;
for (int i = 0; i < data.children.size(); i++) {
-
data.children[i]->_propagate_ready();
}
data.blocked--;
@@ -208,13 +199,13 @@ void Node::_propagate_enter_tree() {
data.tree = data.parent->data.tree;
data.depth = data.parent->data.depth + 1;
} else {
-
data.depth = 1;
}
data.viewport = Object::cast_to<Viewport>(this);
- if (!data.viewport && data.parent)
+ if (!data.viewport && data.parent) {
data.viewport = data.parent->data.viewport;
+ }
data.inside_tree = true;
@@ -224,10 +215,7 @@ void Node::_propagate_enter_tree() {
notification(NOTIFICATION_ENTER_TREE);
- if (get_script_instance()) {
-
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree, nullptr, 0);
- }
+ GDVIRTUAL_CALL(_enter_tree);
emit_signal(SceneStringNames::get_singleton()->tree_entered);
@@ -237,9 +225,9 @@ void Node::_propagate_enter_tree() {
//block while adding children
for (int i = 0; i < data.children.size(); i++) {
-
- if (!data.children[i]->is_inside_tree()) // could have been added in enter_tree
+ if (!data.children[i]->is_inside_tree()) { // could have been added in enter_tree
data.children[i]->_propagate_enter_tree();
+ }
}
data.blocked--;
@@ -251,7 +239,6 @@ void Node::_propagate_enter_tree() {
}
void Node::_propagate_after_exit_tree() {
-
data.blocked++;
for (int i = 0; i < data.children.size(); i++) {
data.children[i]->_propagate_after_exit_tree();
@@ -261,7 +248,6 @@ void Node::_propagate_after_exit_tree() {
}
void Node::_propagate_exit_tree() {
-
//block while removing children
#ifdef DEBUG_ENABLED
@@ -270,21 +256,19 @@ void Node::_propagate_exit_tree() {
data.blocked++;
for (int i = data.children.size() - 1; i >= 0; i--) {
-
data.children[i]->_propagate_exit_tree();
}
data.blocked--;
- if (get_script_instance()) {
+ GDVIRTUAL_CALL(_exit_tree);
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, nullptr, 0);
- }
emit_signal(SceneStringNames::get_singleton()->tree_exiting);
notification(NOTIFICATION_EXIT_TREE, true);
- if (data.tree)
+ if (data.tree) {
data.tree->node_removed(this);
+ }
// exit groups
@@ -295,8 +279,9 @@ void Node::_propagate_exit_tree() {
data.viewport = nullptr;
- if (data.tree)
+ if (data.tree) {
data.tree->tree_changed();
+ }
data.inside_tree = false;
data.ready_notified = false;
@@ -305,19 +290,46 @@ 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_COND_MSG(p_child->data.parent != this, "Child is not a child of this node.");
+
+ // We need to check whether node is internal and move it only in the relevant node range.
+ if (p_child->_is_internal_front()) {
+ ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_front, vformat("Invalid new child position: %d. Child is internal.", p_pos));
+ _move_child(p_child, p_pos);
+ } else if (p_child->_is_internal_back()) {
+ ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_back, vformat("Invalid new child position: %d. Child is internal.", p_pos));
+ _move_child(p_child, data.children.size() - data.internal_children_back + p_pos);
+ } else {
+ ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child position: %d.", p_pos));
+ _move_child(p_child, p_pos + data.internal_children_front);
+ }
+}
+
+void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup).");
// Specifying one place beyond the end
// means the same as moving to the last position
- if (p_pos == data.children.size())
- p_pos--;
+ if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly.
+ if (p_child->_is_internal_front()) {
+ if (p_pos == data.internal_children_front) {
+ p_pos--;
+ }
+ } else if (p_child->_is_internal_back()) {
+ if (p_pos == data.children.size()) {
+ p_pos--;
+ }
+ } else {
+ if (p_pos == data.children.size() - data.internal_children_back) {
+ p_pos--;
+ }
+ }
+ }
- if (p_child->data.pos == p_pos)
+ if (p_child->data.pos == p_pos) {
return; //do nothing
+ }
int motion_from = MIN(p_pos, p_child->data.pos);
int motion_to = MAX(p_pos, p_child->data.pos);
@@ -332,7 +344,6 @@ void Node::move_child(Node *p_child, int p_pos) {
data.blocked++;
//new pos first
for (int i = motion_from; i <= motion_to; i++) {
-
data.children[i]->data.pos = i;
}
// notification second
@@ -341,314 +352,265 @@ void Node::move_child(Node *p_child, int p_pos) {
data.children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
for (const Map<StringName, GroupData>::Element *E = p_child->data.grouped.front(); E; E = E->next()) {
- if (E->get().group)
+ if (E->get().group) {
E->get().group->changed = true;
+ }
}
data.blocked--;
}
void Node::raise() {
-
- if (!data.parent)
+ if (!data.parent) {
return;
+ }
- data.parent->move_child(this, data.parent->data.children.size() - 1);
+ // Internal children move within a different index range.
+ if (_is_internal_front()) {
+ data.parent->move_child(this, data.parent->data.internal_children_front - 1);
+ } else if (_is_internal_back()) {
+ data.parent->move_child(this, data.parent->data.internal_children_back - 1);
+ } else {
+ data.parent->move_child(this, data.parent->get_child_count(false) - 1);
+ }
}
void Node::add_child_notify(Node *p_child) {
-
// to be used when not wanted
}
void Node::remove_child_notify(Node *p_child) {
-
// to be used when not wanted
}
void Node::move_child_notify(Node *p_child) {
-
// to be used when not wanted
}
void Node::set_physics_process(bool p_process) {
-
- if (data.physics_process == p_process)
+ if (data.physics_process == p_process) {
return;
+ }
data.physics_process = p_process;
- if (data.physics_process)
+ if (data.physics_process) {
add_to_group("physics_process", false);
- else
+ } else {
remove_from_group("physics_process");
-
- _change_notify("physics_process");
+ }
}
bool Node::is_physics_processing() const {
-
return data.physics_process;
}
void Node::set_physics_process_internal(bool p_process_internal) {
-
- if (data.physics_process_internal == p_process_internal)
+ if (data.physics_process_internal == p_process_internal) {
return;
+ }
data.physics_process_internal = p_process_internal;
- if (data.physics_process_internal)
+ if (data.physics_process_internal) {
add_to_group("physics_process_internal", false);
- else
+ } else {
remove_from_group("physics_process_internal");
-
- _change_notify("physics_process_internal");
+ }
}
bool Node::is_physics_processing_internal() const {
-
return data.physics_process_internal;
}
-void Node::set_pause_mode(PauseMode p_mode) {
-
- if (data.pause_mode == p_mode)
+void Node::set_process_mode(ProcessMode p_mode) {
+ if (data.process_mode == p_mode) {
return;
+ }
- bool prev_inherits = data.pause_mode == PAUSE_MODE_INHERIT;
- data.pause_mode = p_mode;
- if (!is_inside_tree())
- return; //pointless
- if ((data.pause_mode == PAUSE_MODE_INHERIT) == prev_inherits)
- return; ///nothing changed
+ if (!is_inside_tree()) {
+ data.process_mode = p_mode;
+ return;
+ }
- Node *owner = nullptr;
+ bool prev_can_process = can_process();
+ bool prev_enabled = _is_enabled();
- if (data.pause_mode == PAUSE_MODE_INHERIT) {
+ data.process_mode = p_mode;
- if (data.parent)
- owner = data.parent->data.pause_owner;
+ if (data.process_mode == PROCESS_MODE_INHERIT) {
+ if (data.parent) {
+ data.process_owner = data.parent->data.owner;
+ } else {
+ data.process_owner = nullptr;
+ }
} else {
- owner = this;
+ data.process_owner = this;
}
- _propagate_pause_owner(owner);
-}
+ bool next_can_process = can_process();
+ bool next_enabled = _is_enabled();
-Node::PauseMode Node::get_pause_mode() const {
+ int pause_notification = 0;
- return data.pause_mode;
-}
+ if (prev_can_process && !next_can_process) {
+ pause_notification = NOTIFICATION_PAUSED;
+ } else if (!prev_can_process && next_can_process) {
+ pause_notification = NOTIFICATION_UNPAUSED;
+ }
-void Node::_propagate_pause_owner(Node *p_owner) {
+ int enabled_notification = 0;
- if (this != p_owner && data.pause_mode != PAUSE_MODE_INHERIT)
- return;
- data.pause_owner = p_owner;
- for (int i = 0; i < data.children.size(); i++) {
+ if (prev_enabled && !next_enabled) {
+ enabled_notification = NOTIFICATION_DISABLED;
+ } else if (!prev_enabled && next_enabled) {
+ enabled_notification = NOTIFICATION_ENABLED;
+ }
- data.children[i]->_propagate_pause_owner(p_owner);
+ _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
+ // It's very expensive during runtime to change, so editor-only
+ if (Engine::get_singleton()->is_editor_hint()) {
+ get_tree()->emit_signal(SNAME("tree_process_mode_changed"));
}
+#endif
}
-void Node::set_network_master(int p_peer_id, bool p_recursive) {
+void Node::_propagate_pause_notification(bool p_enable) {
+ bool prev_can_process = _can_process(!p_enable);
+ bool next_can_process = _can_process(p_enable);
- data.network_master = p_peer_id;
-
- if (p_recursive) {
- for (int i = 0; i < data.children.size(); i++) {
+ if (prev_can_process && !next_can_process) {
+ notification(NOTIFICATION_PAUSED);
+ } else if (!prev_can_process && next_can_process) {
+ notification(NOTIFICATION_UNPAUSED);
+ }
- data.children[i]->set_network_master(p_peer_id, true);
- }
+ for (int i = 0; i < data.children.size(); i++) {
+ data.children[i]->_propagate_pause_notification(p_enable);
}
}
-int Node::get_network_master() const {
-
- return data.network_master;
+Node::ProcessMode Node::get_process_mode() const {
+ return data.process_mode;
}
-bool Node::is_network_master() const {
+void Node::_propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification) {
+ data.process_owner = p_owner;
- ERR_FAIL_COND_V(!is_inside_tree(), false);
-
- return get_multiplayer()->get_network_unique_id() == data.network_master;
-}
-
-/***** RPC CONFIG ********/
+ if (p_pause_notification != 0) {
+ notification(p_pause_notification);
+ }
-uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode) {
+ if (p_enabled_notification != 0) {
+ notification(p_enabled_notification);
+ }
- 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_properties.size() - 1) | (1 << 15);
- } else {
- int c_mid = (~(1 << 15)) & mid;
- data.rpc_methods.write[c_mid].mode = p_mode;
- return mid;
+ 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_pause_notification, p_enabled_notification);
+ }
}
}
-uint16_t Node::rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode) {
+void Node::set_multiplayer_authority(int p_peer_id, bool p_recursive) {
+ data.multiplayer_authority = p_peer_id;
- 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;
+ if (p_recursive) {
+ for (int i = 0; i < data.children.size(); i++) {
+ data.children[i]->set_multiplayer_authority(p_peer_id, true);
+ }
}
}
-/***** RPC FUNCTIONS ********/
-
-void Node::rpc(const StringName &p_method, VARIANT_ARG_DECLARE) {
-
- VARIANT_ARGPTRS;
+int Node::get_multiplayer_authority() const {
+ return data.multiplayer_authority;
+}
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL)
- break;
- argc++;
- }
+bool Node::is_multiplayer_authority() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
- rpcp(0, false, p_method, argptr, argc);
+ return get_multiplayer()->get_unique_id() == data.multiplayer_authority;
}
-void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
-
- VARIANT_ARGPTRS;
+/***** RPC CONFIG ********/
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL)
- break;
- argc++;
+uint16_t Node::rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc_mode, Multiplayer::TransferMode p_transfer_mode, int p_channel) {
+ for (int i = 0; i < data.rpc_methods.size(); i++) {
+ if (data.rpc_methods[i].name == p_method) {
+ Multiplayer::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);
+ }
}
-
- rpcp(p_peer_id, false, p_method, argptr, argc);
+ // New method
+ Multiplayer::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);
}
-void Node::rpc_unreliable(const StringName &p_method, VARIANT_ARG_DECLARE) {
+/***** RPC FUNCTIONS ********/
+void Node::rpc(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)
+ if (argptr[i]->get_type() == Variant::NIL) {
break;
+ }
argc++;
}
- rpcp(0, true, p_method, argptr, argc);
+ rpcp(0, p_method, argptr, argc);
}
-void Node::rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
-
+void Node::rpc_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)
+ 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) {
-
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) {
+ 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();
}
Variant Node::_rpc_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) {
- 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, false, 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) {
- 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;
@@ -662,59 +624,34 @@ Variant Node::_rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Ca
return Variant();
}
- if (p_args[1]->get_type() != Variant::STRING) {
+ 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, true, 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();
}
-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);
-}
-
-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);
+ get_multiplayer()->rpcp(this, p_peer_id, p_method, p_arg, p_argcount);
}
-//////////// end of rpc
Ref<MultiplayerAPI> Node::get_multiplayer() const {
- if (multiplayer.is_valid())
+ if (multiplayer.is_valid()) {
return multiplayer;
- if (!is_inside_tree())
+ }
+ if (!is_inside_tree()) {
return Ref<MultiplayerAPI>();
+ }
return get_tree()->get_multiplayer();
}
@@ -723,191 +660,132 @@ Ref<MultiplayerAPI> Node::get_custom_multiplayer() const {
}
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;
+Vector<Multiplayer::RPCConfig> Node::get_node_rpc_methods() const {
+ return data.rpc_methods;
}
-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();
-}
+//////////// end of rpc
-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;
+bool Node::can_process_notification(int p_what) const {
+ switch (p_what) {
+ case NOTIFICATION_PHYSICS_PROCESS:
+ return data.physics_process;
+ case NOTIFICATION_PROCESS:
+ return data.process;
+ case NOTIFICATION_INTERNAL_PROCESS:
+ return data.process_internal;
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS:
+ return data.physics_process_internal;
}
- return MultiplayerAPI::RPC_MODE_DISABLED;
+
+ return true;
}
-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));
+bool Node::can_process() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
+ return _can_process(get_tree()->is_paused());
}
-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);
+bool Node::_can_process(bool p_paused) 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 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;
+ if (process_mode == PROCESS_MODE_DISABLED) {
+ return false;
+ } else if (process_mode == PROCESS_MODE_ALWAYS) {
+ return true;
}
- 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;
+ if (p_paused) {
+ return process_mode == PROCESS_MODE_WHEN_PAUSED;
+ } else {
+ return process_mode == PROCESS_MODE_PAUSABLE;
}
- 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));
-}
+bool Node::_is_enabled() const {
+ ProcessMode process_mode;
-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);
+ 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;
}
- }
- return rpc_list.md5_text();
-}
-
-bool Node::can_process_notification(int p_what) const {
- switch (p_what) {
- case NOTIFICATION_PHYSICS_PROCESS: return data.physics_process;
- case NOTIFICATION_PROCESS: return data.idle_process;
- case NOTIFICATION_INTERNAL_PROCESS: return data.idle_process_internal;
- case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: return data.physics_process_internal;
+ } else {
+ process_mode = data.process_mode;
}
- return true;
+ return (process_mode != PROCESS_MODE_DISABLED);
}
-bool Node::can_process() const {
-
+bool Node::is_enabled() const {
ERR_FAIL_COND_V(!is_inside_tree(), false);
-
- if (get_tree()->is_paused()) {
-
- if (data.pause_mode == PAUSE_MODE_STOP)
- return false;
- if (data.pause_mode == PAUSE_MODE_PROCESS)
- return true;
- if (data.pause_mode == PAUSE_MODE_INHERIT) {
-
- if (!data.pause_owner)
- return false; //clearly no pause owner by default
-
- if (data.pause_owner->data.pause_mode == PAUSE_MODE_PROCESS)
- return true;
-
- if (data.pause_owner->data.pause_mode == PAUSE_MODE_STOP)
- return false;
- }
- }
-
- return true;
+ return _is_enabled();
}
-float Node::get_physics_process_delta_time() const {
-
- if (data.tree)
+double Node::get_physics_process_delta_time() const {
+ if (data.tree) {
return data.tree->get_physics_process_time();
- else
+ } else {
return 0;
+ }
}
-float Node::get_process_delta_time() const {
-
- if (data.tree)
- return data.tree->get_idle_process_time();
- else
+double Node::get_process_delta_time() const {
+ if (data.tree) {
+ return data.tree->get_process_time();
+ } else {
return 0;
+ }
}
-void Node::set_process(bool p_idle_process) {
-
- if (data.idle_process == p_idle_process)
+void Node::set_process(bool p_process) {
+ if (data.process == p_process) {
return;
+ }
- data.idle_process = p_idle_process;
-
- if (data.idle_process)
- add_to_group("idle_process", false);
- else
- remove_from_group("idle_process");
+ data.process = p_process;
- _change_notify("idle_process");
+ if (data.process) {
+ add_to_group("process", false);
+ } else {
+ remove_from_group("process");
+ }
}
bool Node::is_processing() const {
-
- return data.idle_process;
+ return data.process;
}
-void Node::set_process_internal(bool p_idle_process_internal) {
-
- if (data.idle_process_internal == p_idle_process_internal)
+void Node::set_process_internal(bool p_process_internal) {
+ if (data.process_internal == p_process_internal) {
return;
+ }
- data.idle_process_internal = p_idle_process_internal;
-
- if (data.idle_process_internal)
- add_to_group("idle_process_internal", false);
- else
- remove_from_group("idle_process_internal");
+ data.process_internal = p_process_internal;
- _change_notify("idle_process_internal");
+ if (data.process_internal) {
+ add_to_group("process_internal", false);
+ } else {
+ remove_from_group("process_internal");
+ }
}
bool Node::is_processing_internal() const {
-
- return data.idle_process_internal;
+ return data.process_internal;
}
void Node::set_process_priority(int p_priority) {
@@ -919,11 +797,11 @@ void Node::set_process_priority(int p_priority) {
}
if (is_processing()) {
- data.tree->make_group_changed("idle_process");
+ data.tree->make_group_changed("process");
}
if (is_processing_internal()) {
- data.tree->make_group_changed("idle_process_internal");
+ data.tree->make_group_changed("process_internal");
}
if (is_physics_processing()) {
@@ -936,23 +814,24 @@ void Node::set_process_priority(int p_priority) {
}
int Node::get_process_priority() const {
-
return data.process_priority;
}
void Node::set_process_input(bool p_enable) {
-
- if (p_enable == data.input)
+ if (p_enable == data.input) {
return;
+ }
data.input = p_enable;
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
return;
+ }
- if (p_enable)
+ if (p_enable) {
add_to_group("_vp_input" + itos(get_viewport()->get_instance_id()));
- else
+ } else {
remove_from_group("_vp_input" + itos(get_viewport()->get_instance_id()));
+ }
}
bool Node::is_processing_input() const {
@@ -960,17 +839,19 @@ bool Node::is_processing_input() const {
}
void Node::set_process_unhandled_input(bool p_enable) {
-
- if (p_enable == data.unhandled_input)
+ if (p_enable == data.unhandled_input) {
return;
+ }
data.unhandled_input = p_enable;
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
return;
+ }
- if (p_enable)
+ if (p_enable) {
add_to_group("_vp_unhandled_input" + itos(get_viewport()->get_instance_id()));
- else
+ } else {
remove_from_group("_vp_unhandled_input" + itos(get_viewport()->get_instance_id()));
+ }
}
bool Node::is_processing_unhandled_input() const {
@@ -978,17 +859,19 @@ bool Node::is_processing_unhandled_input() const {
}
void Node::set_process_unhandled_key_input(bool p_enable) {
-
- if (p_enable == data.unhandled_key_input)
+ if (p_enable == data.unhandled_key_input) {
return;
+ }
data.unhandled_key_input = p_enable;
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
return;
+ }
- if (p_enable)
+ if (p_enable) {
add_to_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id()));
- else
+ } else {
remove_from_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id()));
+ }
}
bool Node::is_processing_unhandled_key_input() const {
@@ -996,46 +879,27 @@ bool Node::is_processing_unhandled_key_input() const {
}
StringName Node::get_name() const {
-
return data.name;
}
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;
if (data.parent) {
-
data.parent->_validate_child_name(this);
}
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();
}
@@ -1049,13 +913,11 @@ void Node::init_node_hrcr() {
}
void Node::set_human_readable_collision_renaming(bool p_enabled) {
-
node_hrcr = p_enabled;
}
#ifdef TOOLS_ENABLED
String Node::validate_child_name(Node *p_child) {
-
StringName name = p_child->data.name;
_generate_serial_child_name(p_child, name);
return name;
@@ -1063,11 +925,9 @@ String Node::validate_child_name(Node *p_child) {
#endif
void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
-
/* Make sure the name is unique */
if (node_hrcr || p_force_human_readable) {
-
//this approach to autoset node names is human readable but very slow
//it's turned on while running in the editor
@@ -1076,13 +936,12 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
p_child->data.name = name;
} else {
-
//this approach to autoset node names is fast but not as readable
//it's the default and reserves the '@' character for unique names.
bool unique = true;
- if (p_child->data.name == StringName() || p_child->data.name.operator String()[0] == '@') {
+ if (p_child->data.name == StringName()) {
//new unique name must be assigned
unique = false;
} else {
@@ -1091,8 +950,9 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
int cc = data.children.size();
for (int i = 0; i < cc; i++) {
- if (children[i] == p_child)
+ if (children[i] == p_child) {
continue;
+ }
if (children[i]->data.name == p_child->data.name) {
unique = false;
break;
@@ -1101,7 +961,6 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
}
if (!unique) {
-
ERR_FAIL_COND(!node_hrcr_count.ref());
String name = "@" + String(p_child->get_name()) + "@" + itos(node_hrcr_count.get());
p_child->data.name = name;
@@ -1111,7 +970,6 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
// Return s + 1 as if it were an integer
String increase_numeric_string(const String &s) {
-
String res = s;
bool carry = res.length() > 0;
@@ -1119,7 +977,7 @@ String increase_numeric_string(const String &s) {
if (!carry) {
break;
}
- CharType n = s[i];
+ char32_t n = s[i];
if (n == '9') { // keep carry as true: 9 + 1
res[i] = '0';
} else {
@@ -1136,13 +994,12 @@ 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.
- switch (ProjectSettings::get_singleton()->get("node/name_casing").operator int()) {
+ switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) {
case NAME_CASING_PASCAL_CASE:
break;
case NAME_CASING_CAMEL_CASE: {
@@ -1161,11 +1018,10 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
const Node *const *children_ptr = data.children.ptr();
{
-
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) {
@@ -1182,7 +1038,7 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
String name_string = name;
String nums;
for (int i = name_string.length() - 1; i >= 0; i--) {
- CharType n = name_string[i];
+ char32_t n = name_string[i];
if (n >= '0' && n <= '9') {
nums = String::chr(name_string[i]) + nums;
} else {
@@ -1235,6 +1091,10 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
p_child->data.pos = data.children.size();
data.children.push_back(p_child);
p_child->data.parent = this;
+
+ if (data.internal_children_back > 0) {
+ _move_child(p_child, data.children.size() - data.internal_children_back - 1);
+ }
p_child->notification(NOTIFICATION_PARENTED);
if (data.tree) {
@@ -1247,44 +1107,53 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
add_child_notify(p_child);
}
-void Node::add_child(Node *p_child, bool p_legible_unique_name) {
-
+void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_internal) {
ERR_FAIL_NULL(p_child);
- ERR_FAIL_COND_MSG(p_child == this, "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 */
_validate_child_name(p_child, p_legible_unique_name);
-
_add_child_nocheck(p_child, p_child->data.name);
-}
-
-void Node::add_child_below_node(Node *p_node, Node *p_child, bool p_legible_unique_name) {
- ERR_FAIL_NULL(p_node);
- ERR_FAIL_NULL(p_child);
+ if (p_internal == INTERNAL_MODE_FRONT) {
+ _move_child(p_child, data.internal_children_front);
+ data.internal_children_front++;
+ } else if (p_internal == INTERNAL_MODE_BACK) {
+ if (data.internal_children_back > 0) {
+ _move_child(p_child, data.children.size() - 1, true);
+ }
+ data.internal_children_back++;
+ }
+}
- add_child(p_child, p_legible_unique_name);
+void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
+ ERR_FAIL_NULL(p_sibling);
+ ERR_FAIL_NULL(data.parent);
+ ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself!
+ ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_sibling() failed. Consider using call_deferred(\"add_sibling\", sibling) instead.");
- if (is_a_parent_of(p_node)) {
- move_child(p_child, p_node->get_index() + 1);
- } else {
- WARN_PRINT("Cannot move under node " + p_node->get_name() + " as " + p_child->get_name() + " does not share a parent.");
+ InternalMode internal = INTERNAL_MODE_DISABLED;
+ if (_is_internal_front()) { // The sibling will have the same internal status.
+ internal = INTERNAL_MODE_FRONT;
+ } else if (_is_internal_back()) {
+ internal = INTERNAL_MODE_BACK;
}
+
+ data.parent->add_child(p_sibling, p_legible_unique_name, internal);
+ data.parent->_move_child(p_sibling, get_index() + 1);
}
void Node::_propagate_validate_owner() {
-
if (data.owner) {
-
bool found = false;
Node *parent = data.parent;
while (parent) {
-
if (parent == data.owner) {
-
found = true;
break;
}
@@ -1293,20 +1162,17 @@ void Node::_propagate_validate_owner() {
}
if (!found) {
-
data.owner->data.owned.erase(data.OW);
data.owner = nullptr;
}
}
for (int i = 0; i < data.children.size(); i++) {
-
data.children[i]->_propagate_validate_owner();
}
}
void Node::remove_child(Node *p_child) {
-
ERR_FAIL_NULL(p_child);
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, remove_node() failed. Consider using call_deferred(\"remove_child\", child) instead.");
@@ -1322,19 +1188,22 @@ void Node::remove_child(Node *p_child) {
if (idx == -1) { //maybe removed while unparenting or something and index was not updated, so just in case the above fails, try this.
for (int i = 0; i < child_count; i++) {
-
if (children[i] == p_child) {
-
idx = i;
break;
}
}
}
- 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
+ // If internal child, update the counter.
+ if (p_child->_is_internal_front()) {
+ data.internal_children_front--;
+ } else if (p_child->_is_internal_back()) {
+ data.internal_children_back--;
+ }
p_child->_set_tree(nullptr);
//}
@@ -1349,7 +1218,6 @@ void Node::remove_child(Node *p_child) {
children = data.children.ptrw();
for (int i = idx; i < child_count; i++) {
-
children[i]->data.pos = i;
children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
@@ -1365,32 +1233,45 @@ void Node::remove_child(Node *p_child) {
}
}
-int Node::get_child_count() const {
-
- return data.children.size();
+int Node::get_child_count(bool p_include_internal) const {
+ if (p_include_internal) {
+ return data.children.size();
+ } else {
+ return data.children.size() - data.internal_children_front - data.internal_children_back;
+ }
}
-Node *Node::get_child(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr);
-
- return data.children[p_index];
+Node *Node::get_child(int p_index, bool p_include_internal) const {
+ if (p_include_internal) {
+ if (p_index < 0) {
+ p_index += data.children.size();
+ }
+ ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr);
+ return data.children[p_index];
+ } else {
+ if (p_index < 0) {
+ p_index += data.children.size() - data.internal_children_front - data.internal_children_back;
+ }
+ ERR_FAIL_INDEX_V(p_index, data.children.size() - data.internal_children_front - data.internal_children_back, nullptr);
+ p_index += data.internal_children_front;
+ return data.children[p_index];
+ }
}
Node *Node::_get_child_by_name(const StringName &p_name) const {
-
int cc = data.children.size();
Node *const *cd = data.children.ptr();
for (int i = 0; i < cc; i++) {
- if (cd[i]->data.name == p_name)
+ if (cd[i]->data.name == p_name) {
return cd[i];
+ }
}
return nullptr;
}
Node *Node::get_node_or_null(const NodePath &p_path) const {
-
if (p_path.is_empty()) {
return nullptr;
}
@@ -1403,14 +1284,13 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
if (!p_path.is_absolute()) {
current = const_cast<Node *>(this); //start from this
} else {
-
root = const_cast<Node *>(this);
- while (root->data.parent)
+ while (root->data.parent) {
root = root->data.parent; //start from root
+ }
}
for (int i = 0; i < p_path.get_name_count(); i++) {
-
StringName name = p_path.get_name(i);
Node *next = nullptr;
@@ -1420,25 +1300,23 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
} else if (name == SceneStringNames::get_singleton()->doubledot) { // ..
- if (current == nullptr || !current->data.parent)
+ if (current == nullptr || !current->data.parent) {
return nullptr;
+ }
next = current->data.parent;
} else if (current == nullptr) {
-
- if (name == root->get_name())
+ if (name == root->get_name()) {
next = root;
+ }
} else {
-
next = nullptr;
for (int j = 0; j < current->data.children.size(); j++) {
-
Node *child = current->data.children[j];
if (child->data.name == name) {
-
next = child;
break;
}
@@ -1454,63 +1332,69 @@ 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;
}
bool Node::has_node(const NodePath &p_path) const {
-
return get_node_or_null(p_path) != nullptr;
}
Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) const {
-
Node *const *cptr = data.children.ptr();
int ccount = data.children.size();
for (int i = 0; i < ccount; i++) {
- if (p_owned && !cptr[i]->data.owner)
+ if (p_owned && !cptr[i]->data.owner) {
continue;
- if (cptr[i]->data.name.operator String().match(p_mask))
+ }
+ if (cptr[i]->data.name.operator String().match(p_mask)) {
return cptr[i];
+ }
- if (!p_recursive)
+ if (!p_recursive) {
continue;
+ }
Node *ret = cptr[i]->find_node(p_mask, true, p_owned);
- if (ret)
+ if (ret) {
return ret;
+ }
}
return nullptr;
}
Node *Node::get_parent() const {
-
return data.parent;
}
Node *Node::find_parent(const String &p_mask) const {
-
Node *p = data.parent;
while (p) {
-
- if (p->data.name.operator String().match(p_mask))
+ if (p->data.name.operator String().match(p_mask)) {
return p;
+ }
p = p->data.parent;
}
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) {
-
- if (p == this)
+ if (p == this) {
return true;
+ }
p = p->data.parent;
}
@@ -1518,7 +1402,6 @@ bool Node::is_a_parent_of(const Node *p_node) const {
}
bool Node::is_greater_than(const Node *p_node) const {
-
ERR_FAIL_NULL_V(p_node, false);
ERR_FAIL_COND_V(!data.inside_tree, false);
ERR_FAIL_COND_V(!p_node->data.inside_tree, false);
@@ -1561,7 +1444,6 @@ bool Node::is_greater_than(const Node *p_node) const {
bool res;
while (true) {
-
// using -2 since out-of-tree or nonroot nodes have -1
int this_idx = (idx >= data.depth) ? -2 : this_stack[idx];
int that_idx = (idx >= p_node->data.depth) ? -2 : that_stack[idx];
@@ -1583,18 +1465,19 @@ bool Node::is_greater_than(const Node *p_node) const {
}
void Node::get_owned_by(Node *p_by, List<Node *> *p_owned) {
-
- if (data.owner == p_by)
+ if (data.owner == p_by) {
p_owned->push_back(this);
+ }
- for (int i = 0; i < get_child_count(); i++)
+ for (int i = 0; i < get_child_count(); i++) {
get_child(i)->get_owned_by(p_by, p_owned);
+ }
}
void Node::_set_owner_nocheck(Node *p_owner) {
-
- if (data.owner == p_owner)
+ if (data.owner == p_owner) {
return;
+ }
ERR_FAIL_COND(data.owner);
data.owner = p_owner;
@@ -1603,9 +1486,7 @@ void Node::_set_owner_nocheck(Node *p_owner) {
}
void Node::set_owner(Node *p_owner) {
-
if (data.owner) {
-
data.owner->data.owned.erase(data.OW);
data.OW = nullptr;
data.owner = nullptr;
@@ -1613,14 +1494,14 @@ void Node::set_owner(Node *p_owner) {
ERR_FAIL_COND(p_owner == this);
- if (!p_owner)
+ if (!p_owner) {
return;
+ }
Node *check = this->get_parent();
bool owner_valid = false;
while (check) {
-
if (check == p_owner) {
owner_valid = true;
break;
@@ -1633,22 +1514,21 @@ void Node::set_owner(Node *p_owner) {
_set_owner_nocheck(p_owner);
}
-Node *Node::get_owner() const {
+Node *Node::get_owner() const {
return data.owner;
}
Node *Node::find_common_parent_with(const Node *p_node) const {
-
- if (this == p_node)
+ if (this == p_node) {
return const_cast<Node *>(p_node);
+ }
Set<const Node *> visited;
const Node *n = this;
while (n) {
-
visited.insert(n);
n = n->data.parent;
}
@@ -1656,31 +1536,31 @@ Node *Node::find_common_parent_with(const Node *p_node) const {
const Node *common_parent = p_node;
while (common_parent) {
-
- if (visited.has(common_parent))
+ if (visited.has(common_parent)) {
break;
+ }
common_parent = common_parent->data.parent;
}
- if (!common_parent)
+ if (!common_parent) {
return nullptr;
+ }
return const_cast<Node *>(common_parent);
}
NodePath Node::get_path_to(const Node *p_node) const {
-
ERR_FAIL_NULL_V(p_node, NodePath());
- if (this == p_node)
+ if (this == p_node) {
return NodePath(".");
+ }
Set<const Node *> visited;
const Node *n = this;
while (n) {
-
visited.insert(n);
n = n->data.parent;
}
@@ -1688,9 +1568,9 @@ NodePath Node::get_path_to(const Node *p_node) const {
const Node *common_parent = p_node;
while (common_parent) {
-
- if (visited.has(common_parent))
+ if (visited.has(common_parent)) {
break;
+ }
common_parent = common_parent->data.parent;
}
@@ -1703,7 +1583,6 @@ NodePath Node::get_path_to(const Node *p_node) const {
n = p_node;
while (n != common_parent) {
-
path.push_back(n->get_name());
n = n->data.parent;
}
@@ -1712,22 +1591,21 @@ NodePath Node::get_path_to(const Node *p_node) const {
StringName up = String("..");
while (n != common_parent) {
-
path.push_back(up);
n = n->data.parent;
}
- path.invert();
+ path.reverse();
return NodePath(path, false);
}
NodePath Node::get_path() const {
-
ERR_FAIL_COND_V_MSG(!is_inside_tree(), NodePath(), "Cannot get path of node as it is not in a scene tree.");
- if (data.path_cache)
+ if (data.path_cache) {
return *data.path_cache;
+ }
const Node *n = this;
@@ -1738,7 +1616,7 @@ NodePath Node::get_path() const {
n = n->data.parent;
}
- path.invert();
+ path.reverse();
data.path_cache = memnew(NodePath(path, true));
@@ -1746,16 +1624,15 @@ NodePath Node::get_path() const {
}
bool Node::is_in_group(const StringName &p_identifier) const {
-
return data.grouped.has(p_identifier);
}
void Node::add_to_group(const StringName &p_identifier, bool p_persistent) {
-
ERR_FAIL_COND(!p_identifier.operator String().length());
- if (data.grouped.has(p_identifier))
+ if (data.grouped.has(p_identifier)) {
return;
+ }
GroupData gd;
@@ -1771,33 +1648,31 @@ void Node::add_to_group(const StringName &p_identifier, bool p_persistent) {
}
void Node::remove_from_group(const StringName &p_identifier) {
-
ERR_FAIL_COND(!data.grouped.has(p_identifier));
Map<StringName, GroupData>::Element *E = data.grouped.find(p_identifier);
ERR_FAIL_COND(!E);
- if (data.tree)
+ if (data.tree) {
data.tree->remove_from_group(E->key(), this);
+ }
data.grouped.erase(E);
}
Array Node::_get_groups() const {
-
Array groups;
List<GroupInfo> gi;
get_groups(&gi);
- for (List<GroupInfo>::Element *E = gi.front(); E; E = E->next()) {
- groups.push_back(E->get().name);
+ for (const GroupInfo &E : gi) {
+ groups.push_back(E.name);
}
return groups;
}
void Node::get_groups(List<GroupInfo> *p_groups) const {
-
for (const Map<StringName, GroupData>::Element *E = data.grouped.front(); E; E = E->next()) {
GroupInfo gi;
gi.name = E->key();
@@ -1807,7 +1682,6 @@ void Node::get_groups(List<GroupInfo> *p_groups) const {
}
int Node::get_persistent_group_count() const {
-
int count = 0;
for (const Map<StringName, GroupData>::Element *E = data.grouped.front(); E; E = E->next()) {
@@ -1818,8 +1692,8 @@ int Node::get_persistent_group_count() const {
return count;
}
-void Node::_print_tree_pretty(const String &prefix, const bool last) {
+void Node::_print_tree_pretty(const String &prefix, const bool last) {
String new_prefix = last ? String::utf8(" â”–â•´") : String::utf8(" â” â•´");
print_line(prefix + new_prefix + String(get_name()));
for (int i = 0; i < data.children.size(); i++) {
@@ -1833,21 +1707,19 @@ void Node::print_tree_pretty() {
}
void Node::print_tree() {
-
_print_tree(this);
}
void Node::_print_tree(const Node *p_node) {
print_line(String(p_node->get_path_to(this)));
- for (int i = 0; i < data.children.size(); i++)
+ for (int i = 0; i < data.children.size(); i++) {
data.children[i]->_print_tree(p_node);
+ }
}
void Node::_propagate_reverse_notification(int p_notification) {
-
data.blocked++;
for (int i = data.children.size() - 1; i >= 0; i--) {
-
data.children[i]->_propagate_reverse_notification(p_notification);
}
@@ -1856,71 +1728,83 @@ void Node::_propagate_reverse_notification(int p_notification) {
}
void Node::_propagate_deferred_notification(int p_notification, bool p_reverse) {
-
ERR_FAIL_COND(!is_inside_tree());
data.blocked++;
- if (!p_reverse)
+ if (!p_reverse) {
MessageQueue::get_singleton()->push_notification(this, p_notification);
+ }
for (int i = 0; i < data.children.size(); i++) {
-
data.children[i]->_propagate_deferred_notification(p_notification, p_reverse);
}
- if (p_reverse)
+ if (p_reverse) {
MessageQueue::get_singleton()->push_notification(this, p_notification);
+ }
data.blocked--;
}
void Node::propagate_notification(int p_notification) {
-
data.blocked++;
notification(p_notification);
for (int i = 0; i < data.children.size(); i++) {
-
data.children[i]->propagate_notification(p_notification);
}
data.blocked--;
}
void Node::propagate_call(const StringName &p_method, const Array &p_args, const bool p_parent_first) {
-
data.blocked++;
- if (p_parent_first && has_method(p_method))
+ if (p_parent_first && has_method(p_method)) {
callv(p_method, p_args);
+ }
for (int i = 0; i < data.children.size(); i++) {
data.children[i]->propagate_call(p_method, p_args, p_parent_first);
}
- if (!p_parent_first && has_method(p_method))
+ if (!p_parent_first && has_method(p_method)) {
callv(p_method, p_args);
+ }
data.blocked--;
}
void Node::_propagate_replace_owner(Node *p_owner, Node *p_by_owner) {
- if (get_owner() == p_owner)
+ if (get_owner() == p_owner) {
set_owner(p_by_owner);
+ }
data.blocked++;
- for (int i = 0; i < data.children.size(); i++)
+ for (int i = 0; i < data.children.size(); i++) {
data.children[i]->_propagate_replace_owner(p_owner, p_by_owner);
+ }
data.blocked--;
}
-int Node::get_index() const {
+int Node::get_index(bool p_include_internal) const {
+ // p_include_internal = false doesn't make sense if the node is internal.
+ ERR_FAIL_COND_V_MSG(!p_include_internal && (_is_internal_front() || _is_internal_back()), -1, "Node is internal. Can't get index with 'include_internal' being false.");
+ if (data.parent && !p_include_internal) {
+ return data.pos - data.parent->data.internal_children_front;
+ }
return data.pos;
}
-void Node::remove_and_skip() {
+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);
Node *new_owner = get_owner();
@@ -1928,12 +1812,12 @@ void Node::remove_and_skip() {
List<Node *> children;
while (true) {
-
bool clear = true;
for (int i = 0; i < data.children.size(); i++) {
Node *c_node = data.children[i];
- if (!c_node->get_owner())
+ if (!c_node->get_owner()) {
continue;
+ }
remove_child(c_node);
c_node->_propagate_replace_owner(this, nullptr);
@@ -1942,12 +1826,12 @@ void Node::remove_and_skip() {
break;
}
- if (clear)
+ if (clear) {
break;
+ }
}
- while (!children.empty()) {
-
+ while (!children.is_empty()) {
Node *c_node = children.front()->get();
data.parent->add_child(c_node);
c_node->_propagate_replace_owner(nullptr, new_owner);
@@ -1958,130 +1842,134 @@ void Node::remove_and_skip() {
}
void Node::set_filename(const String &p_filename) {
-
data.filename = p_filename;
}
-String Node::get_filename() const {
+String Node::get_filename() const {
return data.filename;
}
void Node::set_editor_description(const String &p_editor_description) {
-
- set_meta("_editor_description_", p_editor_description);
+ data.editor_description = p_editor_description;
}
-String Node::get_editor_description() const {
- if (has_meta("_editor_description_")) {
- return get_meta("_editor_description_");
- } else {
- return "";
- }
+String Node::get_editor_description() const {
+ return data.editor_description;
}
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));
- NodePath p = get_path_to(p_node);
+ ERR_FAIL_COND(!is_ancestor_of(p_node));
if (!p_editable) {
- data.editable_instances.erase(p);
+ 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 {
- data.editable_instances[p] = true;
+ p_node->data.editable_instance = true;
}
}
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);
- NodePath p = get_path_to(p_node);
- return data.editable_instances.has(p);
+ if (!p_node) {
+ return false; // Easier, null is never editable. :)
+ }
+ ERR_FAIL_COND_V(!is_ancestor_of(p_node), false);
+ return p_node->data.editable_instance;
}
-void Node::set_editable_instances(const HashMap<NodePath, int> &p_editable_instances) {
+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);
- data.editable_instances = p_editable_instances;
+ 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;
}
-HashMap<NodePath, int> Node::get_editable_instances() const {
+String Node::to_string() {
+ if (get_script_instance()) {
+ bool valid;
+ String ret = get_script_instance()->to_string(&valid);
+ if (valid) {
+ return ret;
+ }
+ }
- return data.editable_instances;
+ 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;
}
Ref<SceneState> Node::get_scene_instance_state() const {
-
return data.instance_state;
}
void Node::set_scene_inherited_state(const Ref<SceneState> &p_state) {
-
data.inherited_state = p_state;
}
Ref<SceneState> Node::get_scene_inherited_state() const {
-
return data.inherited_state;
}
void Node::set_scene_instance_load_placeholder(bool p_enable) {
-
data.use_placeholder = p_enable;
}
bool Node::get_scene_instance_load_placeholder() const {
-
return data.use_placeholder;
}
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);
InstancePlaceholder *nip = memnew(InstancePlaceholder);
nip->set_instance_path(ip->get_instance_path());
node = nip;
} else if ((p_flags & DUPLICATE_USE_INSTANCING) && get_filename() != String()) {
-
Ref<PackedScene> res = ResourceLoader::load(get_filename());
ERR_FAIL_COND_V(res.is_null(), nullptr);
PackedScene::GenEditState ges = PackedScene::GEN_EDIT_STATE_DISABLED;
#ifdef TOOLS_ENABLED
- if (p_flags & DUPLICATE_FROM_EDITOR)
+ if (p_flags & DUPLICATE_FROM_EDITOR) {
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)
+ if (!node) {
memdelete(obj);
+ }
ERR_FAIL_COND_V(!node, nullptr);
}
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;
@@ -2090,29 +1978,35 @@ 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);
+ }
}
}
}
for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
-
Node *current_node = node->get_node(get_path_to(N->get()));
ERR_CONTINUE(!current_node);
@@ -2127,25 +2021,24 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
List<PropertyInfo> plist;
N->get()->get_property_list(&plist);
- for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
-
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
+ for (const PropertyInfo &E : plist) {
+ if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
continue;
- String name = E->get().name;
- if (name == script_property_name)
+ }
+ String name = E.name;
+ if (name == script_property_name) {
continue;
+ }
Variant value = N->get()->get(name).duplicate(true);
- if (E->get().usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE) {
-
+ if (E.usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE) {
Resource *res = Object::cast_to<Resource>(value);
if (res) { // Duplicate only if it's a resource
current_node->set(name, res->duplicate());
}
} else {
-
current_node->set(name, value);
}
}
@@ -2156,34 +2049,35 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
}
#ifdef TOOLS_ENABLED
- if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap)
+ if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap) {
r_duplimap->insert(this, node);
+ }
#endif
if (p_flags & DUPLICATE_GROUPS) {
List<GroupInfo> gi;
get_groups(&gi);
- for (List<GroupInfo>::Element *E = gi.front(); E; E = E->next()) {
-
+ for (const GroupInfo &E : gi) {
#ifdef TOOLS_ENABLED
- if ((p_flags & DUPLICATE_FROM_EDITOR) && !E->get().persistent)
+ if ((p_flags & DUPLICATE_FROM_EDITOR) && !E.persistent) {
continue;
+ }
#endif
- node->add_to_group(E->get().name, E->get().persistent);
+ node->add_to_group(E.name, E.persistent);
}
}
for (int i = 0; i < get_child_count(); i++) {
-
- if (get_child(i)->data.parent_owned)
+ 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
+ }
Node *dup = get_child(i)->_duplicate(p_flags, r_duplimap);
if (!dup) {
-
memdelete(node);
return nullptr;
}
@@ -2194,27 +2088,23 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
}
}
- for (List<const Node *>::Element *E = hidden_roots.front(); E; E = E->next()) {
-
- Node *parent = node->get_node(get_path_to(E->get()->data.parent));
+ for (const Node *&E : hidden_roots) {
+ Node *parent = node->get_node(get_path_to(E->data.parent));
if (!parent) {
-
memdelete(node);
return nullptr;
}
- Node *dup = E->get()->_duplicate(p_flags, r_duplimap);
+ Node *dup = E->_duplicate(p_flags, r_duplimap);
if (!dup) {
-
memdelete(node);
return nullptr;
}
parent->add_child(dup);
- int pos = E->get()->get_index();
+ int pos = E->get_index();
if (pos < parent->get_child_count() - 1) {
-
parent->move_child(dup, pos);
}
}
@@ -2223,7 +2113,6 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
}
Node *Node::duplicate(int p_flags) const {
-
Node *dupe = _duplicate(p_flags);
if (dupe && (p_flags & DUPLICATE_SIGNALS)) {
@@ -2235,9 +2124,17 @@ Node *Node::duplicate(int p_flags) const {
#ifdef TOOLS_ENABLED
Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const {
+ return duplicate_from_editor(r_duplimap, Map<RES, RES>());
+}
+Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap, const Map<RES, RES> &p_resource_remap) const {
Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANCING | DUPLICATE_FROM_EDITOR, &r_duplimap);
+ // This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated.
+ if (!p_resource_remap.is_empty()) {
+ remap_node_resources(dupe, p_resource_remap);
+ }
+
// 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
@@ -2245,187 +2142,121 @@ Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const {
return dupe;
}
-#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;
+void Node::remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_remap) const {
+ List<PropertyInfo> props;
+ p_node->get_property_list(&props);
- 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 {
+ for (const PropertyInfo &E : props) {
+ if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
- 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()) + ".");
+ Variant v = p_node->get(E.name);
+ if (v.is_ref()) {
+ RES res = v;
+ if (res.is_valid()) {
+ if (p_resource_remap.has(res)) {
+ p_node->set(E.name, p_resource_remap[res]);
+ remap_nested_resources(res, p_resource_remap);
+ }
+ }
}
}
- 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);
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ remap_node_resources(p_node->get_child(i), p_resource_remap);
}
+}
- 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();
+void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resource_remap) const {
+ List<PropertyInfo> props;
+ p_resource->get_property_list(&props);
- if (p_reown_map.has(owner))
- owner = p_reown_map[owner];
+ for (const PropertyInfo &E : props) {
+ if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
- 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);
+ Variant v = p_resource->get(E.name);
+ if (v.is_ref()) {
+ RES res = v;
+ if (res.is_valid()) {
+ if (p_resource_remap.has(res)) {
+ p_resource->set(E.name, p_resource_remap[res]);
+ remap_nested_resources(res, p_resource_remap);
+ }
}
}
}
-
- for (int i = 0; i < get_child_count(); i++) {
-
- get_child(i)->_duplicate_and_reown(node, p_reown_map);
- }
}
+#endif
// 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 && (get_owner() != p_original && get_owner() != p_original->get_owner()))
+ if ((this != p_original) && !(p_original->is_ancestor_of(this))) {
return;
+ }
- List<Connection> conns;
- get_all_signal_connections(&conns);
+ List<const Node *> process_list;
+ process_list.push_back(this);
+ while (!process_list.is_empty()) {
+ const Node *n = process_list.front()->get();
+ process_list.pop_front();
- for (List<Connection>::Element *E = conns.front(); E; E = E->next()) {
+ List<Connection> conns;
+ n->get_all_signal_connections(&conns);
- if (E->get().flags & CONNECT_PERSIST) {
- //user connected
- NodePath p = p_original->get_path_to(this);
- Node *copy = p_copy->get_node(p);
+ for (const Connection &E : conns) {
+ if (E.flags & CONNECT_PERSIST) {
+ //user connected
+ NodePath p = p_original->get_path_to(n);
+ Node *copy = p_copy->get_node(p);
- Node *target = Object::cast_to<Node>(E->get().callable.get_object());
- if (!target) {
- continue;
- }
- NodePath ptarget = p_original->get_path_to(target);
+ Node *target = Object::cast_to<Node>(E.callable.get_object());
+ if (!target) {
+ continue;
+ }
+ NodePath ptarget = p_original->get_path_to(target);
- Node *copytarget = target;
+ Node *copytarget = target;
- // Attempt to find a path to the duplicate target, if it seems it's not part
- // of the duplicated and not yet parented hierarchy then at least try to connect
- // to the same target as the original
+ // Attempt to find a path to the duplicate target, if it seems it's not part
+ // of the duplicated and not yet parented hierarchy then at least try to connect
+ // to the same target as the original
- if (p_copy->has_node(ptarget))
- copytarget = p_copy->get_node(ptarget);
+ if (p_copy->has_node(ptarget)) {
+ copytarget = p_copy->get_node(ptarget);
+ }
- if (copy && copytarget) {
- const Callable copy_callable = Callable(copytarget, E->get().callable.get_method());
- if (!copy->is_connected(E->get().signal.get_name(), copy_callable)) {
- copy->connect(E->get().signal.get_name(), copy_callable, E->get().binds, E->get().flags);
+ if (copy && copytarget) {
+ const Callable copy_callable = Callable(copytarget, E.callable.get_method());
+ if (!copy->is_connected(E.signal.get_name(), copy_callable)) {
+ copy->connect(E.signal.get_name(), copy_callable, E.binds, E.flags);
+ }
}
}
}
- }
-
- for (int i = 0; i < get_child_count(); i++) {
- get_child(i)->_duplicate_signals(p_original, p_copy);
- }
-}
-
-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);
+ for (int i = 0; i < n->get_child_count(); i++) {
+ process_list.push_back(n->get_child(i));
+ }
}
-
- // 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)
+ if (p_node->get_owner() == p_by) {
p_owned->push_back(p_node);
+ }
for (int i = 0; i < p_node->get_child_count(); i++) {
-
find_owned_by(p_by, p_node->get_child(i), p_owned);
}
}
-struct _NodeReplaceByPair {
-
- String name;
- Variant value;
-};
-
-void Node::replace_by(Node *p_node, bool p_keep_data) {
-
+void Node::replace_by(Node *p_node, bool p_keep_groups) {
ERR_FAIL_NULL(p_node);
ERR_FAIL_COND(p_node->data.parent);
@@ -2433,48 +2264,33 @@ void Node::replace_by(Node *p_node, bool p_keep_data) {
List<Node *> owned_by_owner;
Node *owner = (data.owner == this) ? p_node : data.owner;
- List<_NodeReplaceByPair> replace_data;
-
- if (p_keep_data) {
-
- List<PropertyInfo> plist;
- get_property_list(&plist);
-
- for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
-
- _NodeReplaceByPair rd;
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
- continue;
- rd.name = E->get().name;
- rd.value = get(rd.name);
- }
-
+ if (p_keep_groups) {
List<GroupInfo> groups;
get_groups(&groups);
- for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next())
- p_node->add_to_group(E->get().name, E->get().persistent);
+ for (const GroupInfo &E : groups) {
+ p_node->add_to_group(E.name, E.persistent);
+ }
}
_replace_connections_target(p_node);
if (data.owner) {
- for (int i = 0; i < get_child_count(); i++)
+ for (int i = 0; i < get_child_count(); i++) {
find_owned_by(data.owner, get_child(i), &owned_by_owner);
+ }
}
Node *parent = data.parent;
int pos_in_parent = data.pos;
if (data.parent) {
-
parent->remove_child(this);
parent->add_child(p_node);
parent->move_child(p_node, pos_in_parent);
}
while (get_child_count()) {
-
Node *child = get_child(0);
remove_child(child);
if (!child->is_owned_by_parent()) {
@@ -2484,74 +2300,71 @@ void Node::replace_by(Node *p_node, bool p_keep_data) {
}
p_node->set_owner(owner);
- for (int i = 0; i < owned.size(); i++)
+ for (int i = 0; i < owned.size(); i++) {
owned[i]->set_owner(p_node);
+ }
- for (int i = 0; i < owned_by_owner.size(); i++)
+ for (int i = 0; i < owned_by_owner.size(); i++) {
owned_by_owner[i]->set_owner(owner);
+ }
p_node->set_filename(get_filename());
-
- for (List<_NodeReplaceByPair>::Element *E = replace_data.front(); E; E = E->next()) {
-
- p_node->set(E->get().name, E->get().value);
- }
}
void Node::_replace_connections_target(Node *p_new_target) {
-
List<Connection> cl;
get_signals_connected_to_this(&cl);
- for (List<Connection>::Element *E = cl.front(); E; E = E->next()) {
-
- Connection &c = E->get();
-
+ for (const Connection &c : cl) {
if (c.flags & CONNECT_PERSIST) {
c.signal.get_object()->disconnect(c.signal.get_name(), Callable(this, c.callable.get_method()));
bool valid = p_new_target->has_method(c.callable.get_method()) || Ref<Script>(p_new_target->get_script()).is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.callable.get_method());
- 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);
}
}
}
Vector<Variant> Node::make_binds(VARIANT_ARG_DECLARE) {
-
Vector<Variant> ret;
- if (p_arg1.get_type() == Variant::NIL)
+ if (p_arg1.get_type() == Variant::NIL) {
return ret;
- else
+ } else {
ret.push_back(p_arg1);
+ }
- if (p_arg2.get_type() == Variant::NIL)
+ if (p_arg2.get_type() == Variant::NIL) {
return ret;
- else
+ } else {
ret.push_back(p_arg2);
+ }
- if (p_arg3.get_type() == Variant::NIL)
+ if (p_arg3.get_type() == Variant::NIL) {
return ret;
- else
+ } else {
ret.push_back(p_arg3);
+ }
- if (p_arg4.get_type() == Variant::NIL)
+ if (p_arg4.get_type() == Variant::NIL) {
return ret;
- else
+ } else {
ret.push_back(p_arg4);
+ }
- if (p_arg5.get_type() == Variant::NIL)
+ if (p_arg5.get_type() == Variant::NIL) {
return ret;
- else
+ } else {
ret.push_back(p_arg5);
+ }
return ret;
}
bool Node::has_node_and_resource(const NodePath &p_path) const {
-
- if (!has_node(p_path))
+ if (!has_node(p_path)) {
return false;
+ }
RES res;
Vector<StringName> leftover_path;
Node *node = get_node_and_resource(p_path, res, leftover_path, false);
@@ -2560,21 +2373,22 @@ bool Node::has_node_and_resource(const NodePath &p_path) const {
}
Array Node::_get_node_and_resource(const NodePath &p_path) {
-
RES res;
Vector<StringName> leftover_path;
Node *node = get_node_and_resource(p_path, res, leftover_path, false);
Array result;
- if (node)
+ if (node) {
result.push_back(node);
- else
+ } else {
result.push_back(Variant());
+ }
- if (res.is_valid())
+ if (res.is_valid()) {
result.push_back(res);
- else
+ } else {
result.push_back(Variant());
+ }
result.push_back(NodePath(Vector<StringName>(), leftover_path, false));
@@ -2582,15 +2396,14 @@ Array Node::_get_node_and_resource(const NodePath &p_path) {
}
Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property) const {
-
Node *node = get_node(p_path);
r_res = RES();
r_leftover_subpath = Vector<StringName>();
- if (!node)
+ if (!node) {
return nullptr;
+ }
if (p_path.get_subname_count()) {
-
int j = 0;
// If not p_last_is_property, we shouldn't consider the last one as part of the resource
for (; j < p_path.get_subname_count() - (int)p_last_is_property; j++) {
@@ -2618,7 +2431,6 @@ Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<Str
}
void Node::_set_tree(SceneTree *p_tree) {
-
SceneTree *tree_changed_a = nullptr;
SceneTree *tree_changed_b = nullptr;
@@ -2633,7 +2445,6 @@ void Node::_set_tree(SceneTree *p_tree) {
data.tree = p_tree;
if (data.tree) {
-
_propagate_enter_tree();
if (!data.parent || data.parent->data.ready_notified) { // No parent (root) or parent ready
_propagate_ready(); //reverse_notification(NOTIFICATION_READY);
@@ -2642,21 +2453,24 @@ void Node::_set_tree(SceneTree *p_tree) {
tree_changed_b = data.tree;
}
- if (tree_changed_a)
+ if (tree_changed_a) {
tree_changed_a->tree_changed();
- if (tree_changed_b)
+ }
+ if (tree_changed_b) {
tree_changed_b->tree_changed();
+ }
}
#ifdef DEBUG_ENABLED
static void _Node_debug_sn(Object *p_obj) {
-
Node *n = Object::cast_to<Node>(p_obj);
- if (!n)
+ if (!n) {
return;
+ }
- if (n->is_inside_tree())
+ if (n->is_inside_tree()) {
return;
+ }
Node *p = n;
while (p->get_parent()) {
@@ -2664,28 +2478,26 @@ static void _Node_debug_sn(Object *p_obj) {
}
String path;
- if (p == n)
+ if (p == n) {
path = n->get_name();
- else
+ } else {
path = String(p->get_name()) + "/" + p->get_path_to(n);
+ }
print_line(itos(p_obj->get_instance_id()) + " - Stray Node: " + path + " (Type: " + n->get_class() + ")");
}
#endif // DEBUG_ENABLED
void Node::_print_stray_nodes() {
-
print_stray_nodes();
}
void Node::print_stray_nodes() {
-
#ifdef DEBUG_ENABLED
ObjectDB::debug_objects(_Node_debug_sn);
#endif
}
void Node::queue_delete() {
-
if (is_inside_tree()) {
get_tree()->queue_delete(this);
} else {
@@ -2693,26 +2505,24 @@ void Node::queue_delete() {
}
}
-Array Node::_get_children() const {
-
- Array arr;
- int cc = get_child_count();
+TypedArray<Node> Node::_get_children(bool p_include_internal) const {
+ TypedArray<Node> arr;
+ int cc = get_child_count(p_include_internal);
arr.resize(cc);
- for (int i = 0; i < cc; i++)
- arr[i] = get_child(i);
+ for (int i = 0; i < cc; i++) {
+ arr[i] = get_child(i, p_include_internal);
+ }
return arr;
}
void Node::set_import_path(const NodePath &p_import_path) {
-
#ifdef TOOLS_ENABLED
data.import_path = p_import_path;
#endif
}
NodePath Node::get_import_path() const {
-
#ifdef TOOLS_ENABLED
return data.import_path;
#else
@@ -2721,55 +2531,70 @@ NodePath Node::get_import_path() const {
}
static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<String> *r_options) {
-
#ifdef TOOLS_ENABLED
- const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
+ const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
#else
const String quote_style = "\"";
#endif
- if (p_node != p_base && !p_node->get_owner())
+ if (p_node != p_base && !p_node->get_owner()) {
return;
+ }
String n = p_base->get_path_to(p_node);
- r_options->push_back(quote_style + n + quote_style);
+ r_options->push_back(n.quote(quote_style));
for (int i = 0; i < p_node->get_child_count(); i++) {
_add_nodes_to_options(p_base, p_node->get_child(i), r_options);
}
}
void Node::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-
String pf = p_function;
if ((pf == "has_node" || pf == "get_node") && p_idx == 0) {
-
_add_nodes_to_options(this, this, r_options);
}
Object::get_argument_options(p_function, p_idx, r_options);
}
void Node::clear_internal_tree_resource_paths() {
-
clear_internal_resource_paths();
for (int i = 0; i < data.children.size(); i++) {
data.children[i]->clear_internal_tree_resource_paths();
}
}
-String Node::get_configuration_warning() 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");
+TypedArray<String> Node::get_configuration_warnings() const {
+ Vector<String> warnings;
+ if (GDVIRTUAL_CALL(_get_configuration_warnings, warnings)) {
+ TypedArray<String> ret;
+ ret.resize(warnings.size());
+ for (int i = 0; i < warnings.size(); i++) {
+ ret[i] = warnings[i];
+ }
+ return ret;
}
- return 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())
+ 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
@@ -2784,7 +2609,6 @@ void Node::set_display_folded(bool p_folded) {
}
bool Node::is_displayed_folded() const {
-
return data.display_folded;
}
@@ -2792,22 +2616,52 @@ void Node::request_ready() {
data.ready_first = true;
}
-void Node::_bind_methods() {
+void Node::_call_input(const Ref<InputEvent> &p_event) {
+ GDVIRTUAL_CALL(_input, p_event);
+ if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
+ return;
+ }
+ input(p_event);
+}
+void Node::_call_unhandled_input(const Ref<InputEvent> &p_event) {
+ GDVIRTUAL_CALL(_unhandled_input, p_event);
+ if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
+ return;
+ }
+ unhandled_input(p_event);
+}
+void Node::_call_unhandled_key_input(const Ref<InputEvent> &p_event) {
+ GDVIRTUAL_CALL(_unhandled_key_input, p_event);
+ if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
+ return;
+ }
+ unhandled_key_input(p_event);
+}
- GLOBAL_DEF("node/name_num_separator", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("node/name_num_separator", PropertyInfo(Variant::INT, "node/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"));
- GLOBAL_DEF("node/name_casing", NAME_CASING_PASCAL_CASE);
- ProjectSettings::get_singleton()->set_custom_property_info("node/name_casing", PropertyInfo(Variant::INT, "node/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"));
+void Node::input(const Ref<InputEvent> &p_event) {
+}
- ClassDB::bind_method(D_METHOD("add_child_below_node", "preceding_node", "node", "legible_unique_name"), &Node::add_child_below_node, DEFVAL(false));
+void Node::unhandled_input(const Ref<InputEvent> &p_event) {
+}
+
+void Node::unhandled_key_input(const Ref<InputEvent> &p_key_event) {
+}
+
+void Node::_bind_methods() {
+ GLOBAL_DEF("editor/node_naming/name_num_separator", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_num_separator", PropertyInfo(Variant::INT, "editor/node_naming/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"));
+ GLOBAL_DEF("editor/node_naming/name_casing", NAME_CASING_PASCAL_CASE);
+ ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_casing", PropertyInfo(Variant::INT, "editor/node_naming/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"));
+
+ ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "legible_unique_name"), &Node::add_sibling, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_name", "name"), &Node::set_name);
ClassDB::bind_method(D_METHOD("get_name"), &Node::get_name);
- ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name"), &Node::add_child, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
ClassDB::bind_method(D_METHOD("remove_child", "node"), &Node::remove_child);
- ClassDB::bind_method(D_METHOD("get_child_count"), &Node::get_child_count);
- ClassDB::bind_method(D_METHOD("get_children"), &Node::_get_children);
- ClassDB::bind_method(D_METHOD("get_child", "idx"), &Node::get_child);
+ ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript.
+ ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::_get_children, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_child", "idx", "include_internal"), &Node::get_child, DEFVAL(false));
ClassDB::bind_method(D_METHOD("has_node", "path"), &Node::has_node);
ClassDB::bind_method(D_METHOD("get_node", "path"), &Node::get_node);
ClassDB::bind_method(D_METHOD("get_node_or_null", "path"), &Node::get_node_or_null);
@@ -2818,7 +2672,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);
@@ -2831,7 +2685,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner);
ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner);
ClassDB::bind_method(D_METHOD("remove_and_skip"), &Node::remove_and_skip);
- ClassDB::bind_method(D_METHOD("get_index"), &Node::get_index);
+ ClassDB::bind_method(D_METHOD("get_index", "include_internal"), &Node::get_index, DEFVAL(false));
ClassDB::bind_method(D_METHOD("print_tree"), &Node::print_tree);
ClassDB::bind_method(D_METHOD("print_tree_pretty"), &Node::print_tree_pretty);
ClassDB::bind_method(D_METHOD("set_filename", "filename"), &Node::set_filename);
@@ -2852,8 +2706,8 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_processing_unhandled_input"), &Node::is_processing_unhandled_input);
ClassDB::bind_method(D_METHOD("set_process_unhandled_key_input", "enable"), &Node::set_process_unhandled_key_input);
ClassDB::bind_method(D_METHOD("is_processing_unhandled_key_input"), &Node::is_processing_unhandled_key_input);
- ClassDB::bind_method(D_METHOD("set_pause_mode", "mode"), &Node::set_pause_mode);
- ClassDB::bind_method(D_METHOD("get_pause_mode"), &Node::get_pause_mode);
+ ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Node::set_process_mode);
+ ClassDB::bind_method(D_METHOD("get_process_mode"), &Node::get_process_mode);
ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process);
ClassDB::bind_method(D_METHOD("print_stray_nodes"), &Node::_print_stray_nodes);
@@ -2867,12 +2721,15 @@ 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_data"), &Node::replace_by, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder);
ClassDB::bind_method(D_METHOD("get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder);
+ ClassDB::bind_method(D_METHOD("set_editable_instance", "node", "is_editable"), &Node::set_editable_instance);
+ ClassDB::bind_method(D_METHOD("is_editable_instance", "node"), &Node::is_editable_instance);
ClassDB::bind_method(D_METHOD("get_viewport"), &Node::get_viewport);
@@ -2880,23 +2737,22 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("request_ready"), &Node::request_ready);
- ClassDB::bind_method(D_METHOD("set_network_master", "id", "recursive"), &Node::set_network_master, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("get_network_master"), &Node::get_network_master);
+ ClassDB::bind_method(D_METHOD("set_multiplayer_authority", "id", "recursive"), &Node::set_multiplayer_authority, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("get_multiplayer_authority"), &Node::get_multiplayer_authority);
- ClassDB::bind_method(D_METHOD("is_network_master"), &Node::is_network_master);
+ ClassDB::bind_method(D_METHOD("is_multiplayer_authority"), &Node::is_multiplayer_authority);
ClassDB::bind_method(D_METHOD("get_multiplayer"), &Node::get_multiplayer);
ClassDB::bind_method(D_METHOD("get_custom_multiplayer"), &Node::get_custom_multiplayer);
ClassDB::bind_method(D_METHOD("set_custom_multiplayer", "api"), &Node::set_custom_multiplayer);
- ClassDB::bind_method(D_METHOD("rpc_config", "method", "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(Multiplayer::TRANSFER_MODE_RELIABLE), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("_set_editor_description", "editor_description"), &Node::set_editor_description);
- ClassDB::bind_method(D_METHOD("_get_editor_description"), &Node::get_editor_description);
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_editor_description", "_get_editor_description");
+ 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);
ClassDB::bind_method(D_METHOD("_set_import_path", "import_path"), &Node::set_import_path);
ClassDB::bind_method(D_METHOD("_get_import_path"), &Node::get_import_path);
+
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path");
{
@@ -2906,23 +2762,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);
@@ -2940,11 +2787,17 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_PATH_CHANGED);
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);
- BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN);
- BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT);
+ BIND_CONSTANT(NOTIFICATION_WM_WINDOW_FOCUS_IN);
+ BIND_CONSTANT(NOTIFICATION_WM_WINDOW_FOCUS_OUT);
BIND_CONSTANT(NOTIFICATION_WM_CLOSE_REQUEST);
BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST);
BIND_CONSTANT(NOTIFICATION_WM_SIZE_CHANGED);
@@ -2953,91 +2806,76 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
BIND_CONSTANT(NOTIFICATION_CRASH);
BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE);
- BIND_CONSTANT(NOTIFICATION_APP_RESUMED);
- BIND_CONSTANT(NOTIFICATION_APP_PAUSED);
-
- BIND_ENUM_CONSTANT(PAUSE_MODE_INHERIT);
- BIND_ENUM_CONSTANT(PAUSE_MODE_STOP);
- BIND_ENUM_CONSTANT(PAUSE_MODE_PROCESS);
+ BIND_CONSTANT(NOTIFICATION_APPLICATION_RESUMED);
+ BIND_CONSTANT(NOTIFICATION_APPLICATION_PAUSED);
+ BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_IN);
+ BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_OUT);
+ BIND_CONSTANT(NOTIFICATION_TEXT_SERVER_CHANGED);
+
+ BIND_ENUM_CONSTANT(PROCESS_MODE_INHERIT);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_PAUSABLE);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_WHEN_PAUSED);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_DISABLED);
BIND_ENUM_CONSTANT(DUPLICATE_SIGNALS);
BIND_ENUM_CONSTANT(DUPLICATE_GROUPS);
BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS);
BIND_ENUM_CONSTANT(DUPLICATE_USE_INSTANCING);
+ BIND_ENUM_CONSTANT(INTERNAL_MODE_DISABLED);
+ BIND_ENUM_CONSTANT(INTERNAL_MODE_FRONT);
+ BIND_ENUM_CONSTANT(INTERNAL_MODE_BACK);
+
ADD_SIGNAL(MethodInfo("ready"));
ADD_SIGNAL(MethodInfo("renamed"));
ADD_SIGNAL(MethodInfo("tree_entered"));
ADD_SIGNAL(MethodInfo("tree_exiting"));
ADD_SIGNAL(MethodInfo("tree_exited"));
- ADD_GROUP("Pause", "pause_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode");
+ 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_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_GROUP("Process", "process_");
+ 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");
- BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::FLOAT, "delta")));
- BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::FLOAT, "delta")));
- BIND_VMETHOD(MethodInfo("_enter_tree"));
- BIND_VMETHOD(MethodInfo("_exit_tree"));
- BIND_VMETHOD(MethodInfo("_ready"));
- BIND_VMETHOD(MethodInfo("_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_configuration_warning"));
+ ADD_GROUP("Editor Description", "editor_");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "set_editor_description", "get_editor_description");
+
+ GDVIRTUAL_BIND(_process, "delta");
+ GDVIRTUAL_BIND(_physics_process, "delta");
+ GDVIRTUAL_BIND(_enter_tree);
+ GDVIRTUAL_BIND(_exit_tree);
+ GDVIRTUAL_BIND(_ready);
+ GDVIRTUAL_BIND(_get_configuration_warnings);
+ GDVIRTUAL_BIND(_input, "event");
+ GDVIRTUAL_BIND(_unhandled_input, "event");
+ GDVIRTUAL_BIND(_unhandled_key_input, "event");
}
String Node::_get_name_num_separator() {
- switch (ProjectSettings::get_singleton()->get("node/name_num_separator").operator int()) {
- case 0: return "";
- case 1: return " ";
- case 2: return "_";
- case 3: return "-";
+ switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_num_separator").operator int()) {
+ case 0:
+ return "";
+ case 1:
+ return " ";
+ case 2:
+ return "_";
+ case 3:
+ return "-";
}
return " ";
}
Node::Node() {
-
- data.pos = -1;
- data.depth = -1;
- data.blocked = 0;
- data.parent = nullptr;
- data.tree = nullptr;
- data.physics_process = false;
- data.idle_process = false;
- data.process_priority = 0;
- data.physics_process_internal = false;
- data.idle_process_internal = false;
- data.inside_tree = false;
- data.ready_notified = false;
-
- data.owner = nullptr;
- data.OW = nullptr;
- data.input = false;
- data.unhandled_input = false;
- data.unhandled_key_input = false;
- data.pause_mode = PAUSE_MODE_INHERIT;
- data.pause_owner = nullptr;
- data.network_master = 1; //server by default
- data.path_cache = nullptr;
- data.parent_owned = false;
- data.in_constructor = true;
- data.viewport = nullptr;
- data.use_placeholder = false;
- data.display_folded = false;
- data.ready_first = true;
-
orphan_node_count++;
}
Node::~Node() {
-
data.grouped.clear();
data.owned.clear();
data.children.clear();
diff --git a/scene/main/node.h b/scene/main/node.h
index 5de07d506e..198501eeac 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,31 +31,33 @@
#ifndef NODE_H
#define NODE_H
-#include "core/class_db.h"
-#include "core/map.h"
-#include "core/node_path.h"
-#include "core/object.h"
-#include "core/project_settings.h"
-#include "core/script_language.h"
+#include "core/config/project_settings.h"
+#include "core/object/class_db.h"
+#include "core/object/script_language.h"
+#include "core/string/node_path.h"
+#include "core/templates/map.h"
+#include "core/variant/typed_array.h"
#include "scene/main/scene_tree.h"
class Viewport;
class SceneState;
-class Node : public Object {
+class Tween;
+class PropertyTweener;
+class Node : public Object {
GDCLASS(Node, Object);
OBJ_CATEGORY("Nodes");
public:
- enum PauseMode {
-
- PAUSE_MODE_INHERIT,
- PAUSE_MODE_STOP,
- PAUSE_MODE_PROCESS
+ enum ProcessMode {
+ PROCESS_MODE_INHERIT, // same as parent node
+ PROCESS_MODE_PAUSABLE, // process only if not paused
+ PROCESS_MODE_WHEN_PAUSED, // process only if paused
+ PROCESS_MODE_ALWAYS, // process always
+ PROCESS_MODE_DISABLED, // never process
};
enum DuplicateFlags {
-
DUPLICATE_SIGNALS = 1,
DUPLICATE_GROUPS = 2,
DUPLICATE_SCRIPTS = 4,
@@ -65,13 +67,23 @@ public:
#endif
};
- struct Comparator {
+ enum NameCasing {
+ NAME_CASING_PASCAL_CASE,
+ NAME_CASING_CAMEL_CASE,
+ NAME_CASING_SNAKE_CASE
+ };
+ enum InternalMode {
+ INTERNAL_MODE_DISABLED,
+ INTERNAL_MODE_FRONT,
+ INTERNAL_MODE_BACK,
+ };
+
+ struct Comparator {
bool operator()(const Node *p_a, const Node *p_b) const { return p_b->is_greater_than(p_a); }
};
struct ComparatorWithPriority {
-
bool operator()(const Node *p_a, const Node *p_b) const { return p_b->data.process_priority == p_a->data.process_priority ? p_b->is_greater_than(p_a) : p_b->data.process_priority > p_a->data.process_priority; }
};
@@ -79,82 +91,69 @@ public:
private:
struct GroupData {
-
- bool persistent;
- SceneTree::Group *group;
- GroupData() { persistent = false; }
- };
-
- struct NetData {
- StringName name;
- MultiplayerAPI::RPCMode mode;
+ bool persistent = false;
+ SceneTree::Group *group = nullptr;
};
struct Data {
-
String filename;
Ref<SceneState> instance_state;
Ref<SceneState> inherited_state;
- HashMap<NodePath, int> editable_instances;
-
- Node *parent;
- Node *owner;
- Vector<Node *> children; // list of children
- int pos;
- int depth;
- int blocked; // safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
+ Node *parent = nullptr;
+ Node *owner = nullptr;
+ Vector<Node *> children;
+ int internal_children_front = 0;
+ int internal_children_back = 0;
+ int pos = -1;
+ int depth = -1;
+ int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
StringName name;
- SceneTree *tree;
- bool inside_tree;
- bool ready_notified; //this is a small hack, so if a node is added during _ready() to the tree, it correctly gets the _ready() notification
- bool ready_first;
+ SceneTree *tree = nullptr;
+ bool inside_tree = false;
+ bool ready_notified = false; // This is a small hack, so if a node is added during _ready() to the tree, it correctly gets the _ready() notification.
+ bool ready_first = true;
#ifdef TOOLS_ENABLED
- NodePath import_path; //path used when imported, used by scene editors to keep tracking
+ NodePath import_path; // Path used when imported, used by scene editors to keep tracking.
#endif
+ String editor_description;
- Viewport *viewport;
+ Viewport *viewport = nullptr;
Map<StringName, GroupData> grouped;
- List<Node *>::Element *OW; // owned element
+ List<Node *>::Element *OW = nullptr; // Owned element.
List<Node *> owned;
- PauseMode pause_mode;
- Node *pause_owner;
+ ProcessMode process_mode = PROCESS_MODE_INHERIT;
+ Node *process_owner = nullptr;
- int network_master;
- Vector<NetData> rpc_methods;
- Vector<NetData> rpc_properties;
+ int multiplayer_authority = 1; // Server by default.
+ Vector<Multiplayer::RPCConfig> rpc_methods;
- // variables used to properly sort the node when processing, ignored otherwise
- //should move all the stuff below to bits
- bool physics_process;
- bool idle_process;
- int process_priority;
+ // Variables used to properly sort the node when processing, ignored otherwise.
+ // TODO: Should move all the stuff below to bits.
+ bool physics_process = false;
+ bool process = false;
+ int process_priority = 0;
- bool physics_process_internal;
- bool idle_process_internal;
+ bool physics_process_internal = false;
+ bool process_internal = false;
- bool input;
- bool unhandled_input;
- bool unhandled_key_input;
+ bool input = false;
+ bool unhandled_input = false;
+ bool unhandled_key_input = false;
- bool parent_owned;
- bool in_constructor;
- bool use_placeholder;
+ bool parent_owned = false;
+ bool in_constructor = true;
+ bool use_placeholder = false;
- bool display_folded;
+ bool display_folded = false;
+ bool editable_instance = false;
- mutable NodePath *path_cache;
+ mutable NodePath *path_cache = nullptr;
} data;
- enum NameCasing {
- NAME_CASING_PASCAL_CASE,
- NAME_CASING_CAMEL_CASE,
- NAME_CASING_SNAKE_CASE
- };
-
Ref<MultiplayerAPI> multiplayer;
void _print_tree_pretty(const String &prefix, const bool last);
@@ -175,30 +174,28 @@ private:
void _propagate_after_exit_tree();
void _propagate_validate_owner();
void _print_stray_nodes();
- void _propagate_pause_owner(Node *p_owner);
+ 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;
- Array _get_children() const;
+ TypedArray<Node> _get_children(bool p_include_internal = true) const;
Array _get_groups() const;
Variant _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant _rpc_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);
+
+ _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.pos < data.parent->data.internal_children_front; }
+ _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.pos >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
friend class SceneTree;
void _set_tree(SceneTree *p_tree);
+ void _propagate_pause_notification(bool p_enable);
-#ifdef TOOLS_ENABLED
- friend class SceneTreeEditor;
-#endif
- static String invalid_character;
- static bool _validate_node_name(String &p_name);
+ _FORCE_INLINE_ bool _can_process(bool p_paused) const;
+ _FORCE_INLINE_ bool _is_enabled() const;
protected:
void _block() { data.blocked++; }
@@ -216,14 +213,35 @@ protected:
static String _get_name_num_separator();
friend class SceneState;
+ friend class MultiplayerReplicator;
void _add_child_nocheck(Node *p_child, const StringName &p_name);
void _set_owner_nocheck(Node *p_owner);
void _set_name_nocheck(const StringName &p_name);
+ //call from SceneTree
+ void _call_input(const Ref<InputEvent> &p_event);
+ void _call_unhandled_input(const Ref<InputEvent> &p_event);
+ void _call_unhandled_key_input(const Ref<InputEvent> &p_event);
+
+protected:
+ virtual void input(const Ref<InputEvent> &p_event);
+ virtual void unhandled_input(const Ref<InputEvent> &p_event);
+ virtual void unhandled_key_input(const Ref<InputEvent> &p_key_event);
+
+ GDVIRTUAL1(_process, double)
+ GDVIRTUAL1(_physics_process, double)
+ GDVIRTUAL0(_enter_tree)
+ GDVIRTUAL0(_exit_tree)
+ GDVIRTUAL0(_ready)
+ GDVIRTUAL0RC(Vector<String>, _get_configuration_warnings)
+
+ GDVIRTUAL1(_input, Ref<InputEvent>)
+ GDVIRTUAL1(_unhandled_input, Ref<InputEvent>)
+ GDVIRTUAL1(_unhandled_key_input, Ref<InputEvent>)
+
public:
enum {
-
// you can make your own, but don't use the same numbers as other notifications in other nodes
NOTIFICATION_ENTER_TREE = 10,
NOTIFICATION_EXIT_TREE = 11,
@@ -243,12 +261,14 @@ 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,
NOTIFICATION_WM_MOUSE_EXIT = 1003,
- NOTIFICATION_WM_FOCUS_IN = 1004,
- NOTIFICATION_WM_FOCUS_OUT = 1005,
+ NOTIFICATION_WM_WINDOW_FOCUS_IN = 1004,
+ NOTIFICATION_WM_WINDOW_FOCUS_OUT = 1005,
NOTIFICATION_WM_CLOSE_REQUEST = 1006,
NOTIFICATION_WM_GO_BACK_REQUEST = 1007,
NOTIFICATION_WM_SIZE_CHANGED = 1008,
@@ -259,9 +279,15 @@ public:
NOTIFICATION_WM_ABOUT = MainLoop::NOTIFICATION_WM_ABOUT,
NOTIFICATION_CRASH = MainLoop::NOTIFICATION_CRASH,
NOTIFICATION_OS_IME_UPDATE = MainLoop::NOTIFICATION_OS_IME_UPDATE,
- NOTIFICATION_APP_RESUMED = MainLoop::NOTIFICATION_APP_RESUMED,
- NOTIFICATION_APP_PAUSED = MainLoop::NOTIFICATION_APP_PAUSED
-
+ NOTIFICATION_APPLICATION_RESUMED = MainLoop::NOTIFICATION_APPLICATION_RESUMED,
+ NOTIFICATION_APPLICATION_PAUSED = MainLoop::NOTIFICATION_APPLICATION_PAUSED,
+ 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 */
@@ -269,12 +295,12 @@ public:
StringName get_name() const;
void set_name(const String &p_name);
- void add_child(Node *p_child, bool p_legible_unique_name = false);
- void add_child_below_node(Node *p_node, Node *p_child, bool p_legible_unique_name = false);
+ void add_child(Node *p_child, bool p_legible_unique_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
+ void add_sibling(Node *p_sibling, bool p_legible_unique_name = false);
void remove_child(Node *p_child);
- int get_child_count() const;
- Node *get_child(int p_index) const;
+ int get_child_count(bool p_include_internal = true) const;
+ Node *get_child(int p_index, bool p_include_internal = true) const;
bool has_node(const NodePath &p_path) const;
Node *get_node(const NodePath &p_path) const;
Node *get_node_or_null(const NodePath &p_path) const;
@@ -292,7 +318,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;
@@ -304,15 +330,15 @@ public:
bool is_in_group(const StringName &p_identifier) const;
struct GroupInfo {
-
StringName name;
- bool persistent;
+ bool persistent = false;
};
void get_groups(List<GroupInfo> *p_groups) const;
int get_persistent_group_count() const;
void move_child(Node *p_child, int p_pos);
+ void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false);
void raise();
void set_owner(Node *p_owner);
@@ -320,7 +346,9 @@ public:
void get_owned_by(Node *p_by, List<Node *> *p_owned);
void remove_and_skip();
- int get_index() const;
+ int get_index(bool p_include_internal = true) const;
+
+ Ref<Tween> create_tween();
void print_tree();
void print_tree_pretty();
@@ -333,8 +361,9 @@ public:
void set_editable_instance(Node *p_node, bool p_editable);
bool is_editable_instance(const Node *p_node) const;
- void set_editable_instances(const HashMap<NodePath, int> &p_editable_instances);
- HashMap<NodePath, int> get_editable_instances() const;
+ Node *get_deepest_editable_node(Node *p_start_node) const;
+
+ virtual String to_string() override;
/* NOTIFICATIONS */
@@ -344,17 +373,17 @@ public:
/* PROCESSING */
void set_physics_process(bool p_process);
- float get_physics_process_delta_time() const;
+ double get_physics_process_delta_time() const;
bool is_physics_processing() const;
- void set_process(bool p_idle_process);
- float get_process_delta_time() const;
+ void set_process(bool p_process);
+ double get_process_delta_time() const;
bool is_processing() const;
void set_physics_process_internal(bool p_process_internal);
bool is_physics_processing_internal() const;
- void set_process_internal(bool p_idle_process_internal);
+ void set_process_internal(bool p_process_internal);
bool is_processing_internal() const;
void set_process_priority(int p_priority);
@@ -370,9 +399,11 @@ 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;
+ void remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_remap) const;
+ void remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resource_remap) const;
#endif
// used by editors, to save what has changed only
@@ -389,10 +420,11 @@ public:
void replace_by(Node *p_node, bool p_keep_data = false);
- void set_pause_mode(PauseMode p_mode);
- PauseMode get_pause_mode() const;
+ void set_process_mode(ProcessMode p_mode);
+ ProcessMode get_process_mode() const;
bool can_process() const;
bool can_process_notification(int p_what) const;
+ bool is_enabled() const;
void request_ready();
@@ -415,60 +447,36 @@ public:
bool is_owned_by_parent() const;
- void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
+ void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
void clear_internal_tree_resource_paths();
_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;
/* NETWORK */
- void set_network_master(int p_peer_id, bool p_recursive = true);
- 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
+ void set_multiplayer_authority(int p_peer_id, bool p_recursive = true);
+ int get_multiplayer_authority() const;
+ bool is_multiplayer_authority() 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
+ uint16_t rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc_mode, Multiplayer::TransferMode p_transfer_mode, int p_channel = 0); // config a local method for RPC
+ Vector<Multiplayer::RPCConfig> get_node_rpc_methods() const;
- void 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/resource_preloader.cpp b/scene/main/resource_preloader.cpp
index 43a61834eb..cd9560db61 100644
--- a/scene/main/resource_preloader.cpp
+++ b/scene/main/resource_preloader.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,6 @@
#include "resource_preloader.h"
void ResourcePreloader::_set_resources(const Array &p_data) {
-
resources.clear();
ERR_FAIL_COND(p_data.size() != 2);
@@ -41,7 +40,6 @@ void ResourcePreloader::_set_resources(const Array &p_data) {
ERR_FAIL_COND(names.size() != resdata.size());
for (int i = 0; i < resdata.size(); i++) {
-
String name = names[i];
RES resource = resdata[i];
ERR_CONTINUE(!resource.is_valid());
@@ -52,7 +50,6 @@ void ResourcePreloader::_set_resources(const Array &p_data) {
}
Array ResourcePreloader::_get_resources() const {
-
Vector<String> names;
Array arr;
arr.resize(resources.size());
@@ -66,7 +63,6 @@ Array ResourcePreloader::_get_resources() const {
int i = 0;
for (Set<String>::Element *E = sorted_names.front(); E; E = E->next()) {
-
names.set(i, E->get());
arr[i] = resources[E->get()];
i++;
@@ -79,15 +75,12 @@ Array ResourcePreloader::_get_resources() const {
}
void ResourcePreloader::add_resource(const StringName &p_name, const RES &p_resource) {
-
ERR_FAIL_COND(p_resource.is_null());
if (resources.has(p_name)) {
-
StringName new_name;
int idx = 2;
while (true) {
-
new_name = p_name.operator String() + " " + itos(idx);
if (resources.has(new_name)) {
idx++;
@@ -99,18 +92,16 @@ void ResourcePreloader::add_resource(const StringName &p_name, const RES &p_reso
add_resource(new_name, p_resource);
} else {
-
resources[p_name] = p_resource;
}
}
void ResourcePreloader::remove_resource(const StringName &p_name) {
-
ERR_FAIL_COND(!resources.has(p_name));
resources.erase(p_name);
}
-void ResourcePreloader::rename_resource(const StringName &p_from_name, const StringName &p_to_name) {
+void ResourcePreloader::rename_resource(const StringName &p_from_name, const StringName &p_to_name) {
ERR_FAIL_COND(!resources.has(p_from_name));
RES res = resources[p_from_name];
@@ -120,17 +111,15 @@ void ResourcePreloader::rename_resource(const StringName &p_from_name, const Str
}
bool ResourcePreloader::has_resource(const StringName &p_name) const {
-
return resources.has(p_name);
}
-RES ResourcePreloader::get_resource(const StringName &p_name) const {
+RES ResourcePreloader::get_resource(const StringName &p_name) const {
ERR_FAIL_COND_V(!resources.has(p_name), RES());
return resources[p_name];
}
Vector<String> ResourcePreloader::_get_resource_list() const {
-
Vector<String> res;
res.resize(resources.size());
int i = 0;
@@ -142,15 +131,12 @@ Vector<String> ResourcePreloader::_get_resource_list() const {
}
void ResourcePreloader::get_resource_list(List<StringName> *p_list) {
-
for (Map<StringName, RES>::Element *E = resources.front(); E; E = E->next()) {
-
p_list->push_back(E->key());
}
}
void ResourcePreloader::_bind_methods() {
-
ClassDB::bind_method(D_METHOD("_set_resources"), &ResourcePreloader::_set_resources);
ClassDB::bind_method(D_METHOD("_get_resources"), &ResourcePreloader::_get_resources);
diff --git a/scene/main/resource_preloader.h b/scene/main/resource_preloader.h
index 9ad219dd92..1b7ea3fb9f 100644
--- a/scene/main/resource_preloader.h
+++ b/scene/main/resource_preloader.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,6 @@
#include "scene/main/node.h"
class ResourcePreloader : public Node {
-
GDCLASS(ResourcePreloader, Node);
Map<StringName, RES> resources;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index f30a899d69..e1b1b356a9 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,19 +30,20 @@
#include "scene_tree.h"
+#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
-#include "core/input/input_filter.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/message_queue.h"
-#include "core/os/dir_access.h"
+#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
-#include "core/print_string.h"
-#include "core/project_settings.h"
+#include "core/string/print_string.h"
#include "node.h"
+#include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h"
-#include "scene/resources/dynamic_font.h"
+#include "scene/resources/font.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
#include "scene/resources/packed_scene.h"
@@ -54,9 +55,9 @@
#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);
ClassDB::bind_method(D_METHOD("get_time_left"), &SceneTreeTimer::get_time_left);
@@ -65,67 +66,65 @@ void SceneTreeTimer::_bind_methods() {
ADD_SIGNAL(MethodInfo("timeout"));
}
-void SceneTreeTimer::set_time_left(float p_time) {
+void SceneTreeTimer::set_time_left(double p_time) {
time_left = p_time;
}
-float SceneTreeTimer::get_time_left() const {
+double SceneTreeTimer::get_time_left() const {
return time_left;
}
-void SceneTreeTimer::set_pause_mode_process(bool p_pause_mode_process) {
+void SceneTreeTimer::set_process_always(bool p_process_always) {
+ process_always = p_process_always;
+}
- process_pause = p_pause_mode_process;
+bool SceneTreeTimer::is_process_always() {
+ return process_always;
}
-bool SceneTreeTimer::is_pause_mode_process() {
- return process_pause;
+void SceneTreeTimer::set_ignore_time_scale(bool p_ignore) {
+ ignore_time_scale = p_ignore;
}
-void SceneTreeTimer::release_connections() {
+bool SceneTreeTimer::is_ignore_time_scale() {
+ return ignore_time_scale;
+}
+void SceneTreeTimer::release_connections() {
List<Connection> connections;
get_all_signal_connections(&connections);
- for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
- Connection const &connection = E->get();
+ for (const Connection &connection : connections) {
disconnect(connection.signal.get_name(), connection.callable);
}
}
-SceneTreeTimer::SceneTreeTimer() {
- time_left = 0;
- process_pause = true;
-}
+SceneTreeTimer::SceneTreeTimer() {}
void SceneTree::tree_changed() {
-
tree_version++;
emit_signal(tree_changed_name);
}
void SceneTree::node_added(Node *p_node) {
-
emit_signal(node_added_name, p_node);
}
void SceneTree::node_removed(Node *p_node) {
-
if (current_scene == p_node) {
current_scene = nullptr;
}
emit_signal(node_removed_name, p_node);
- if (call_lock > 0)
+ if (call_lock > 0) {
call_skip.insert(p_node);
+ }
}
void SceneTree::node_renamed(Node *p_node) {
-
emit_signal(node_renamed_name, p_node);
}
SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_node) {
-
Map<StringName, Group>::Element *E = group_map.find(p_group);
if (!E) {
E = group_map.insert(p_group, Group());
@@ -139,26 +138,25 @@ SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_nod
}
void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) {
-
Map<StringName, Group>::Element *E = group_map.find(p_group);
ERR_FAIL_COND(!E);
E->get().nodes.erase(p_node);
- if (E->get().nodes.empty())
+ if (E->get().nodes.is_empty()) {
group_map.erase(E);
+ }
}
void SceneTree::make_group_changed(const StringName &p_group) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
- if (E)
+ if (E) {
E->get().changed = true;
+ }
}
void SceneTree::flush_transform_notifications() {
-
SelfList<Node> *n = xform_change_list.first();
while (n) {
-
Node *node = n->self();
SelfList<Node> *nx = n->next();
xform_change_list.remove(n);
@@ -168,18 +166,18 @@ void SceneTree::flush_transform_notifications() {
}
void SceneTree::_flush_ugc() {
-
ugc_locked = true;
while (unique_group_calls.size()) {
-
Map<UGCall, Vector<Variant>>::Element *E = unique_group_calls.front();
Variant v[VARIANT_ARG_MAX];
- for (int i = 0; i < E->get().size(); i++)
+ for (int i = 0; i < E->get().size(); i++) {
v[i] = E->get()[i];
+ }
- 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);
}
@@ -188,11 +186,12 @@ void SceneTree::_flush_ugc() {
}
void SceneTree::_update_group_order(Group &g, bool p_use_priority) {
-
- if (!g.changed)
+ if (!g.changed) {
return;
- if (g.nodes.empty())
+ }
+ if (g.nodes.is_empty()) {
return;
+ }
Node **nodes = g.nodes.ptrw();
int node_count = g.nodes.size();
@@ -208,31 +207,33 @@ void SceneTree::_update_group_order(Group &g, bool p_use_priority) {
}
void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) {
-
Map<StringName, Group>::Element *E = group_map.find(p_group);
- if (!E)
+ if (!E) {
return;
+ }
Group &g = E->get();
- if (g.nodes.empty())
+ if (g.nodes.is_empty()) {
return;
+ }
if (p_call_flags & GROUP_CALL_UNIQUE && !(p_call_flags & GROUP_CALL_REALTIME)) {
-
ERR_FAIL_COND(ugc_locked);
UGCall ug;
ug.call = p_function;
ug.group = p_group;
- if (unique_group_calls.has(ug))
+ if (unique_group_calls.has(ug)) {
return;
+ }
VARIANT_ARGPTRS;
Vector<Variant> args;
for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL)
+ if (argptr[i]->get_type() == Variant::NIL) {
break;
+ }
args.push_back(*argptr[i]);
}
@@ -249,51 +250,47 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou
call_lock++;
if (p_call_flags & GROUP_CALL_REVERSE) {
-
for (int i = node_count - 1; i >= 0; i--) {
-
- if (call_lock && call_skip.has(nodes[i]))
+ if (call_lock && call_skip.has(nodes[i])) {
continue;
+ }
if (p_call_flags & GROUP_CALL_REALTIME) {
- if (p_call_flags & GROUP_CALL_MULTILEVEL)
- nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS);
- else
- nodes[i]->call(p_function, VARIANT_ARG_PASS);
- } else
+ nodes[i]->call(p_function, VARIANT_ARG_PASS);
+ } else {
MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS);
+ }
}
} else {
-
for (int i = 0; i < node_count; i++) {
-
- if (call_lock && call_skip.has(nodes[i]))
+ if (call_lock && call_skip.has(nodes[i])) {
continue;
+ }
if (p_call_flags & GROUP_CALL_REALTIME) {
- if (p_call_flags & GROUP_CALL_MULTILEVEL)
- nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS);
- else
- nodes[i]->call(p_function, VARIANT_ARG_PASS);
- } else
+ nodes[i]->call(p_function, VARIANT_ARG_PASS);
+ } else {
MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS);
+ }
}
}
call_lock--;
- if (call_lock == 0)
+ if (call_lock == 0) {
call_skip.clear();
+ }
}
void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification) {
-
Map<StringName, Group>::Element *E = group_map.find(p_group);
- if (!E)
+ if (!E) {
return;
+ }
Group &g = E->get();
- if (g.nodes.empty())
+ if (g.nodes.is_empty()) {
return;
+ }
_update_group_order(g);
@@ -304,45 +301,47 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr
call_lock++;
if (p_call_flags & GROUP_CALL_REVERSE) {
-
for (int i = node_count - 1; i >= 0; i--) {
-
- if (call_lock && call_skip.has(nodes[i]))
+ if (call_lock && call_skip.has(nodes[i])) {
continue;
+ }
- if (p_call_flags & GROUP_CALL_REALTIME)
+ if (p_call_flags & GROUP_CALL_REALTIME) {
nodes[i]->notification(p_notification);
- else
+ } else {
MessageQueue::get_singleton()->push_notification(nodes[i], p_notification);
+ }
}
} else {
-
for (int i = 0; i < node_count; i++) {
-
- if (call_lock && call_skip.has(nodes[i]))
+ if (call_lock && call_skip.has(nodes[i])) {
continue;
+ }
- if (p_call_flags & GROUP_CALL_REALTIME)
+ if (p_call_flags & GROUP_CALL_REALTIME) {
nodes[i]->notification(p_notification);
- else
+ } else {
MessageQueue::get_singleton()->push_notification(nodes[i], p_notification);
+ }
}
}
call_lock--;
- if (call_lock == 0)
+ if (call_lock == 0) {
call_skip.clear();
+ }
}
void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value) {
-
Map<StringName, Group>::Element *E = group_map.find(p_group);
- if (!E)
+ if (!E) {
return;
+ }
Group &g = E->get();
- if (g.nodes.empty())
+ if (g.nodes.is_empty()) {
return;
+ }
_update_group_order(g);
@@ -353,35 +352,36 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
call_lock++;
if (p_call_flags & GROUP_CALL_REVERSE) {
-
for (int i = node_count - 1; i >= 0; i--) {
-
- if (call_lock && call_skip.has(nodes[i]))
+ if (call_lock && call_skip.has(nodes[i])) {
continue;
+ }
- if (p_call_flags & GROUP_CALL_REALTIME)
+ if (p_call_flags & GROUP_CALL_REALTIME) {
nodes[i]->set(p_name, p_value);
- else
+ } else {
MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value);
+ }
}
} else {
-
for (int i = 0; i < node_count; i++) {
-
- if (call_lock && call_skip.has(nodes[i]))
+ if (call_lock && call_skip.has(nodes[i])) {
continue;
+ }
- if (p_call_flags & GROUP_CALL_REALTIME)
+ if (p_call_flags & GROUP_CALL_REALTIME) {
nodes[i]->set(p_name, p_value);
- else
+ } else {
MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value);
+ }
}
}
call_lock--;
- if (call_lock == 0)
+ if (call_lock == 0) {
call_skip.clear();
+ }
}
void SceneTree::call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) {
@@ -389,40 +389,41 @@ void SceneTree::call_group(const StringName &p_group, const StringName &p_functi
}
void SceneTree::notify_group(const StringName &p_group, int p_notification) {
-
notify_group_flags(0, p_group, p_notification);
}
void SceneTree::set_group(const StringName &p_group, const String &p_name, const Variant &p_value) {
-
set_group_flags(0, p_group, p_name, p_value);
}
-void SceneTree::init() {
+void SceneTree::initialize() {
+ ERR_FAIL_COND(!root);
initialized = true;
root->_set_tree(this);
- MainLoop::init();
+ MainLoop::initialize();
}
-bool SceneTree::iteration(float p_time) {
-
+bool SceneTree::physics_process(double p_time) {
root_lock++;
current_frame++;
flush_transform_notifications();
- MainLoop::iteration(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);
- _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,35 +432,29 @@ bool SceneTree::iteration(float p_time) {
return _quit;
}
-bool SceneTree::idle(float p_time) {
-
- //print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage()));
- //print_line("node count: "+itos(get_node_count()));
- //print_line("TEXTURE RAM: "+itos(RS::get_singleton()->get_render_info(RS::INFO_TEXTURE_MEM_USED)));
-
+bool SceneTree::process(double p_time) {
root_lock++;
- MainLoop::idle(p_time);
+ MainLoop::process(p_time);
- idle_process_time = p_time;
+ process_time = p_time;
if (multiplayer_poll) {
multiplayer->poll();
}
- emit_signal("idle_frame");
+ emit_signal(SNAME("process_frame"));
MessageQueue::get_singleton()->flush(); //small little hack
flush_transform_notifications();
- _notify_group_pause("idle_process_internal", Node::NOTIFICATION_INTERNAL_PROCESS);
- _notify_group_pause("idle_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--;
@@ -470,21 +465,25 @@ bool SceneTree::idle(float p_time) {
List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
-
List<Ref<SceneTreeTimer>>::Element *N = E->next();
- if (pause && !E->get()->is_pause_mode_process()) {
+ if (paused && !E->get()->is_process_always()) {
if (E == L) {
break; //break on last, so if new timers were added during list traversal, ignore them.
}
E = N;
continue;
}
- float time_left = E->get()->get_time_left();
- time_left -= p_time;
+
+ double time_left = E->get()->get_time_left();
+ if (E->get()->is_ignore_time_scale()) {
+ time_left -= Engine::get_singleton()->get_process_step();
+ } else {
+ time_left -= p_time;
+ }
E->get()->set_time_left(time_left);
if (time_left < 0) {
- E->get()->emit_signal("timeout");
+ E->get()->emit_signal(SNAME("timeout"));
timers.erase(E);
}
if (E == L) {
@@ -493,50 +492,76 @@ bool SceneTree::idle(float p_time) {
E = N;
}
+ process_tweens(p_time, false);
+
flush_transform_notifications(); //additional transforms after timers update
_call_idle_callbacks();
#ifdef TOOLS_ENABLED
-
+#ifndef _3D_DISABLED
if (Engine::get_singleton()->is_editor_hint()) {
//simple hack to reload fallback environment if it changed from editor
- String env_path = ProjectSettings::get_singleton()->get("rendering/environment/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()->get_fallback_environment();
+ Ref<Environment> fallback = get_root()->get_world_3d()->get_fallback_environment();
if (fallback.is_valid()) {
cpath = fallback->get_path();
}
if (cpath != env_path) {
-
if (env_path != String()) {
fallback = ResourceLoader::load(env_path);
if (fallback.is_null()) {
//could not load fallback, set as empty
- ProjectSettings::get_singleton()->set("rendering/environment/default_environment", "");
+ ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
}
} else {
fallback.unref();
}
- get_root()->get_world()->set_fallback_environment(fallback);
+ get_root()->get_world_3d()->set_fallback_environment(fallback);
}
}
-
-#endif
+#endif // _3D_DISABLED
+#endif // TOOLS_ENABLED
return _quit;
}
-void SceneTree::finish() {
+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()->clear();
+ tweens.erase(E);
+ }
+ if (E == L) {
+ break;
+ }
+ E = N;
+ }
+}
+void SceneTree::finalize() {
_flush_delete_queue();
_flush_ugc();
initialized = false;
- MainLoop::finish();
+ MainLoop::finalize();
if (root) {
root->_set_tree(nullptr);
@@ -546,29 +571,23 @@ void SceneTree::finish() {
}
// cleanup timers
- for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E; E = E->next()) {
- E->get()->release_connections();
+ for (Ref<SceneTreeTimer> &timer : timers) {
+ timer->release_connections();
}
timers.clear();
}
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;
}
void SceneTree::_main_window_close() {
-
if (accept_quit) {
_quit = true;
}
}
+
void SceneTree::_main_window_go_back() {
if (quit_on_go_back) {
_quit = true;
@@ -576,16 +595,14 @@ void SceneTree::_main_window_go_back() {
}
void SceneTree::_main_window_focus_in() {
- InputFilter *id = InputFilter::get_singleton();
+ Input *id = Input::get_singleton();
if (id) {
id->ensure_touch_mouse_raised();
}
}
void SceneTree::_notification(int p_notification) {
-
switch (p_notification) {
-
case NOTIFICATION_TRANSLATION_CHANGED: {
if (!Engine::get_singleton()->is_editor_hint()) {
get_root()->propagate_notification(p_notification);
@@ -595,10 +612,11 @@ void SceneTree::_notification(int p_notification) {
case NOTIFICATION_OS_IME_UPDATE:
case NOTIFICATION_WM_ABOUT:
case NOTIFICATION_CRASH:
- case NOTIFICATION_APP_RESUMED:
- case NOTIFICATION_APP_PAUSED: {
-
- get_root()->propagate_notification(p_notification);
+ case NOTIFICATION_APPLICATION_RESUMED:
+ case NOTIFICATION_APPLICATION_PAUSED:
+ case NOTIFICATION_APPLICATION_FOCUS_IN:
+ case NOTIFICATION_APPLICATION_FOCUS_OUT: {
+ get_root()->propagate_notification(p_notification); //pass these to nodes, since they are mirrored
} break;
default:
@@ -607,89 +625,74 @@ void SceneTree::_notification(int p_notification) {
};
void SceneTree::set_auto_accept_quit(bool p_enable) {
-
accept_quit = p_enable;
}
void SceneTree::set_quit_on_go_back(bool p_enable) {
-
quit_on_go_back = 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
#ifdef DEBUG_ENABLED
void SceneTree::set_debug_collisions_hint(bool p_enabled) {
-
debug_collisions_hint = p_enabled;
}
bool SceneTree::is_debugging_collisions_hint() const {
-
return debug_collisions_hint;
}
void SceneTree::set_debug_navigation_hint(bool p_enabled) {
-
debug_navigation_hint = p_enabled;
}
bool SceneTree::is_debugging_navigation_hint() const {
-
return debug_navigation_hint;
}
#endif
void SceneTree::set_debug_collisions_color(const Color &p_color) {
-
debug_collisions_color = p_color;
}
Color SceneTree::get_debug_collisions_color() const {
-
return debug_collisions_color;
}
void SceneTree::set_debug_collision_contact_color(const Color &p_color) {
-
debug_collision_contact_color = p_color;
}
Color SceneTree::get_debug_collision_contact_color() const {
-
return debug_collision_contact_color;
}
void SceneTree::set_debug_navigation_color(const Color &p_color) {
-
debug_navigation_color = p_color;
}
Color SceneTree::get_debug_navigation_color() const {
-
return debug_navigation_color;
}
void SceneTree::set_debug_navigation_disabled_color(const Color &p_color) {
-
debug_navigation_disabled_color = p_color;
}
Color SceneTree::get_debug_navigation_disabled_color() const {
-
return debug_navigation_disabled_color;
}
Ref<Material> SceneTree::get_debug_navigation_material() {
-
- if (navigation_material.is_valid())
+ if (navigation_material.is_valid()) {
return navigation_material;
+ }
Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
@@ -704,9 +707,9 @@ Ref<Material> SceneTree::get_debug_navigation_material() {
}
Ref<Material> SceneTree::get_debug_navigation_disabled_material() {
-
- if (navigation_disabled_material.is_valid())
+ if (navigation_disabled_material.is_valid()) {
return navigation_disabled_material;
+ }
Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
@@ -719,10 +722,11 @@ Ref<Material> SceneTree::get_debug_navigation_disabled_material() {
return navigation_disabled_material;
}
-Ref<Material> SceneTree::get_debug_collision_material() {
- if (collision_material.is_valid())
+Ref<Material> SceneTree::get_debug_collision_material() {
+ if (collision_material.is_valid()) {
return collision_material;
+ }
Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
@@ -737,9 +741,9 @@ Ref<Material> SceneTree::get_debug_collision_material() {
}
Ref<ArrayMesh> SceneTree::get_debug_contact_mesh() {
-
- if (debug_contact_mesh.is_valid())
+ if (debug_contact_mesh.is_valid()) {
return debug_contact_mesh;
+ }
debug_contact_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
@@ -773,12 +777,14 @@ Ref<ArrayMesh> SceneTree::get_debug_contact_mesh() {
/* clang-format on */
Vector<int> indices;
- for (int i = 0; i < 8 * 3; i++)
+ for (int i = 0; i < 8 * 3; i++) {
indices.push_back(diamond_faces[i]);
+ }
Vector<Vector3> vertices;
- for (int i = 0; i < 6; i++)
+ for (int i = 0; i < 6; i++) {
vertices.push_back(diamond[i] * 0.1);
+ }
Array arr;
arr.resize(Mesh::ARRAY_MAX);
@@ -792,30 +798,31 @@ Ref<ArrayMesh> SceneTree::get_debug_contact_mesh() {
}
void SceneTree::set_pause(bool p_enabled) {
-
- if (p_enabled == pause)
+ if (p_enabled == paused) {
return;
- pause = p_enabled;
+ }
+ paused = p_enabled;
NavigationServer3D::get_singleton()->set_active(!p_enabled);
PhysicsServer3D::get_singleton()->set_active(!p_enabled);
PhysicsServer2D::get_singleton()->set_active(!p_enabled);
- if (get_root())
- get_root()->propagate_notification(p_enabled ? Node::NOTIFICATION_PAUSED : Node::NOTIFICATION_UNPAUSED);
+ if (get_root()) {
+ get_root()->_propagate_pause_notification(p_enabled);
+ }
}
bool SceneTree::is_paused() const {
-
- return pause;
+ return paused;
}
void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) {
-
Map<StringName, Group>::Element *E = group_map.find(p_group);
- if (!E)
+ if (!E) {
return;
+ }
Group &g = E->get();
- if (g.nodes.empty())
+ if (g.nodes.is_empty()) {
return;
+ }
_update_group_order(g, p_notification == Node::NOTIFICATION_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PROCESS || p_notification == Node::NOTIFICATION_PHYSICS_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
@@ -829,44 +836,37 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
call_lock++;
for (int i = 0; i < node_count; i++) {
-
Node *n = nodes[i];
- if (call_lock && call_skip.has(n))
+ if (call_lock && call_skip.has(n)) {
continue;
+ }
- if (!n->can_process())
+ if (!n->can_process()) {
continue;
- if (!n->can_process_notification(p_notification))
+ }
+ if (!n->can_process_notification(p_notification)) {
continue;
+ }
n->notification(p_notification);
//ERR_FAIL_COND(node_count != g.nodes.size());
}
call_lock--;
- if (call_lock == 0)
+ if (call_lock == 0) {
call_skip.clear();
-}
-
-/*
-void SceneMainLoop::_update_listener_2d() {
-
- if (listener_2d.is_valid()) {
-
- SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() );
}
-
}
-*/
-
-void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport) {
+void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_call_type, const Ref<InputEvent> &p_input, Viewport *p_viewport) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
- if (!E)
+ if (!E) {
return;
+ }
Group &g = E->get();
- if (g.nodes.empty())
+ if (g.nodes.is_empty()) {
return;
+ }
_update_group_order(g);
@@ -877,33 +877,42 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
int node_count = nodes_copy.size();
Node **nodes = nodes_copy.ptrw();
- Variant arg = p_input;
- const Variant *v[1] = { &arg };
-
call_lock++;
for (int i = node_count - 1; i >= 0; i--) {
-
- if (p_viewport->is_input_handled())
+ if (p_viewport->is_input_handled()) {
break;
+ }
Node *n = nodes[i];
- if (call_lock && call_skip.has(n))
+ if (call_lock && call_skip.has(n)) {
continue;
+ }
- if (!n->can_process())
+ if (!n->can_process()) {
continue;
+ }
- n->call_multilevel(p_method, (const Variant **)v, 1);
- //ERR_FAIL_COND(node_count != g.nodes.size());
+ switch (p_call_type) {
+ case CALL_INPUT_TYPE_INPUT:
+ n->_call_input(p_input);
+ break;
+ case CALL_INPUT_TYPE_UNHANDLED_INPUT:
+ n->_call_unhandled_input(p_input);
+ break;
+ case CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT:
+ n->_call_unhandled_key_input(p_input);
+ break;
+ }
}
call_lock--;
- if (call_lock == 0)
+ if (call_lock == 0) {
call_skip.clear();
+ }
}
-Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;
ERR_FAIL_COND_V(p_argcount < 3, Variant());
@@ -917,16 +926,15 @@ Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Cal
Variant v[VARIANT_ARG_MAX];
for (int i = 0; i < MIN(p_argcount - 3, 5); i++) {
-
v[i] = *p_args[i + 3];
}
- 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();
}
Variant SceneTree::_call_group(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
-
r_error.error = Callable::CallError::CALL_OK;
ERR_FAIL_COND_V(p_argcount < 2, Variant());
@@ -938,40 +946,35 @@ Variant SceneTree::_call_group(const Variant **p_args, int p_argcount, Callable:
Variant v[VARIANT_ARG_MAX];
for (int i = 0; i < MIN(p_argcount - 2, 5); i++) {
-
v[i] = *p_args[i + 2];
}
- 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();
}
int64_t SceneTree::get_frame() const {
-
return current_frame;
}
-int64_t SceneTree::get_event_count() const {
-
- return current_event;
-}
Array SceneTree::_get_nodes_in_group(const StringName &p_group) {
-
Array ret;
Map<StringName, Group>::Element *E = group_map.find(p_group);
- if (!E)
+ if (!E) {
return ret;
+ }
_update_group_order(E->get()); //update order just in case
int nc = E->get().nodes.size();
- if (nc == 0)
+ if (nc == 0) {
return ret;
+ }
ret.resize(nc);
Node **ptr = E->get().nodes.ptrw();
for (int i = 0; i < nc; i++) {
-
ret[i] = ptr[i];
}
@@ -979,32 +982,45 @@ Array SceneTree::_get_nodes_in_group(const StringName &p_group) {
}
bool SceneTree::has_group(const StringName &p_identifier) const {
-
return group_map.has(p_identifier);
}
-void SceneTree::get_nodes_in_group(const StringName &p_group, List<Node *> *p_list) {
+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)
+ if (!E) {
return;
+ }
_update_group_order(E->get()); //update order just in case
int nc = E->get().nodes.size();
- if (nc == 0)
+ if (nc == 0) {
return;
+ }
Node **ptr = E->get().nodes.ptrw();
for (int i = 0; i < nc; i++) {
-
p_list->push_back(ptr[i]);
}
}
void SceneTree::_flush_delete_queue() {
-
_THREAD_SAFE_METHOD_
while (delete_queue.size()) {
-
Object *obj = ObjectDB::get_instance(delete_queue.front()->get());
if (obj) {
memdelete(obj);
@@ -1014,7 +1030,6 @@ void SceneTree::_flush_delete_queue() {
}
void SceneTree::queue_delete(Object *p_object) {
-
_THREAD_SAFE_METHOD_
ERR_FAIL_NULL(p_object);
p_object->_is_queued_for_deletion = true;
@@ -1022,7 +1037,6 @@ void SceneTree::queue_delete(Object *p_object) {
}
int SceneTree::get_node_count() const {
-
return node_count;
}
@@ -1033,7 +1047,6 @@ void SceneTree::set_edited_scene_root(Node *p_node) {
}
Node *SceneTree::get_edited_scene_root() const {
-
#ifdef TOOLS_ENABLED
return edited_scene_root;
#else
@@ -1042,18 +1055,15 @@ Node *SceneTree::get_edited_scene_root() const {
}
void SceneTree::set_current_scene(Node *p_scene) {
-
ERR_FAIL_COND(p_scene && p_scene->get_parent() != root);
current_scene = p_scene;
}
Node *SceneTree::get_current_scene() const {
-
return current_scene;
}
void SceneTree::_change_scene(Node *p_to) {
-
if (current_scene) {
memdelete(current_scene);
current_scene = nullptr;
@@ -1075,8 +1085,9 @@ void SceneTree::_change_scene(Node *p_to) {
Error SceneTree::change_scene(const String &p_path) {
Ref<PackedScene> new_scene = ResourceLoader::load(p_path);
- if (new_scene.is_null())
+ if (new_scene.is_null()) {
return ERR_CANT_OPEN;
+ }
return change_scene_to(new_scene);
}
@@ -1084,11 +1095,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;
}
@@ -1099,44 +1110,38 @@ Error SceneTree::reload_current_scene() {
}
void SceneTree::add_current_scene(Node *p_current) {
-
current_scene = p_current;
root->add_child(p_current);
}
-Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pause) {
-
+Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always) {
Ref<SceneTreeTimer> stt;
- stt.instance();
- stt->set_pause_mode_process(p_process_pause);
+ 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");
-}
-
-void SceneTree::_connection_failed() {
-
- emit_signal("connection_failed");
-}
+Array SceneTree::get_processed_tweens() {
+ Array ret;
+ ret.resize(tweens.size());
-void SceneTree::_server_disconnected() {
+ int i = 0;
+ for (const Ref<Tween> &tween : tweens) {
+ ret[i] = tween;
+ i++;
+ }
- emit_signal("server_disconnected");
+ return ret;
}
Ref<MultiplayerAPI> SceneTree::get_multiplayer() const {
@@ -1154,67 +1159,11 @@ 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() {
-
ClassDB::bind_method(D_METHOD("get_root"), &SceneTree::get_root);
ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group);
@@ -1232,11 +1181,13 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause);
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
- ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "pause_mode_process"), &SceneTree::create_timer, DEFVAL(true));
+ 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);
@@ -1262,6 +1213,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);
@@ -1277,43 +1229,27 @@ 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 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")));
ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
- ADD_SIGNAL(MethodInfo("idle_frame"));
+ ADD_SIGNAL(MethodInfo("process_frame"));
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);
@@ -1327,7 +1263,6 @@ SceneTree::IdleCallback SceneTree::idle_callbacks[SceneTree::MAX_IDLE_CALLBACKS]
int SceneTree::idle_callback_count = 0;
void SceneTree::_call_idle_callbacks() {
-
for (int i = 0; i < idle_callback_count; i++) {
idle_callbacks[i]();
}
@@ -1339,13 +1274,12 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) {
}
void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-
if (p_function == "change_scene") {
DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
List<String> directories;
directories.push_back(dir_access->get_current_dir());
- while (!directories.empty()) {
+ while (!directories.is_empty()) {
dir_access->change_dir(directories.back()->get());
directories.pop_back();
@@ -1371,94 +1305,122 @@ void SceneTree::get_argument_options(const StringName &p_function, int p_idx, Li
}
SceneTree::SceneTree() {
-
- if (singleton == nullptr) singleton = this;
- _quit = false;
- accept_quit = true;
- quit_on_go_back = true;
- initialized = false;
-#ifdef DEBUG_ENABLED
- debug_collisions_hint = false;
- debug_navigation_hint = false;
-#endif
- debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.5));
+ if (singleton == nullptr) {
+ singleton = this;
+ }
+ debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.42));
debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8));
debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4));
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
- tree_version = 1;
- physics_process_time = 1;
- idle_process_time = 1;
-
- root = nullptr;
- pause = false;
- current_frame = 0;
- current_event = 0;
- tree_changed_name = "tree_changed";
- node_added_name = "node_added";
- node_removed_name = "node_removed";
- node_renamed_name = "node_renamed";
- ugc_locked = false;
- call_lock = 0;
- root_lock = 0;
- node_count = 0;
+ GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
- //create with mainloop
+ Math::randomize();
+
+ // Create with mainloop.
root = memnew(Window);
root->set_name("root");
- if (!root->get_world().is_valid())
- root->set_world(Ref<World3D>(memnew(World3D)));
+#ifndef _3D_DISABLED
+ if (!root->get_world_3d().is_valid()) {
+ root->set_world_3d(Ref<World3D>(memnew(World3D)));
+ }
+ root->set_as_audio_listener_3d(true);
+#endif // _3D_DISABLED
- // Initialize network state
- multiplayer_poll = true;
+ // Initialize network state.
set_multiplayer(Ref<MultiplayerAPI>(memnew(MultiplayerAPI)));
- //root->set_world_2d( Ref<World2D>( memnew( World2D )));
- root->set_as_audio_listener(true);
root->set_as_audio_listener_2d(true);
current_scene = nullptr;
- int msaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/msaa", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x"));
+ const int msaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/msaa", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
root->set_msaa(Viewport::MSAA(msaa_mode));
- int ssaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/screen_space_aa", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_aa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"));
+ const int ssaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/screen_space_aa", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"));
root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
- { //load default fallback environment
- //get possible extensions
+ 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);
+
+ bool snap_2d_transforms = GLOBAL_DEF("rendering/2d/snap/snap_2d_transforms_to_pixel", false);
+ root->set_snap_2d_transforms_to_pixel(snap_2d_transforms);
+
+ bool snap_2d_vertices = GLOBAL_DEF("rendering/2d/snap/snap_2d_vertices_to_pixel", false);
+ root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
+
+ int shadowmap_size = GLOBAL_DEF("rendering/shadows/shadow_atlas/size", 4096);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384"));
+ GLOBAL_DEF("rendering/shadows/shadow_atlas/size.mobile", 2048);
+ bool shadowmap_16_bits = GLOBAL_DEF("rendering/shadows/shadow_atlas/16_bits", true);
+ int atlas_q0 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_0_subdiv", 2);
+ int atlas_q1 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_1_subdiv", 2);
+ int atlas_q2 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_2_subdiv", 3);
+ int atlas_q3 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_3_subdiv", 4);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+
+ root->set_shadow_atlas_size(shadowmap_size);
+ root->set_shadow_atlas_16_bits(shadowmap_16_bits);
+ root->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0));
+ root->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1));
+ root->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
+ root->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
+
+ Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_DEF("rendering/2d/sdf/oversize", 1)));
+ root->set_sdf_oversize(sdf_oversize);
+ Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_DEF("rendering/2d/sdf/scale", 1)));
+ root->set_sdf_scale(sdf_scale);
+
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/sdf/oversize", PropertyInfo(Variant::INT, "rendering/2d/sdf/oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/sdf/scale", PropertyInfo(Variant::INT, "rendering/2d/sdf/scale", PROPERTY_HINT_ENUM, "100%,50%,25%"));
+
+#ifndef _3D_DISABLED
+ { // Load default fallback environment.
+ // Get possible extensions.
List<String> exts;
ResourceLoader::get_recognized_extensions_for_type("Environment", &exts);
String ext_hint;
- for (List<String>::Element *E = exts.front(); E; E = E->next()) {
- if (ext_hint != String())
+ for (const String &E : exts) {
+ if (ext_hint != String()) {
ext_hint += ",";
- ext_hint += "*." + E->get();
+ }
+ ext_hint += "*." + E;
}
- //get path
- String env_path = GLOBAL_DEF("rendering/environment/default_environment", "");
- //setup property
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint));
+ // Get path.
+ String env_path = GLOBAL_DEF("rendering/environment/defaults/default_environment", "");
+ // Setup property.
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/defaults/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint));
env_path = env_path.strip_edges();
if (env_path != String()) {
Ref<Environment> env = ResourceLoader::load(env_path);
if (env.is_valid()) {
- root->get_world()->set_fallback_environment(env);
+ root->get_world_3d()->set_fallback_environment(env);
} else {
if (Engine::get_singleton()->is_editor_hint()) {
- //file was erased, clear the field.
- ProjectSettings::get_singleton()->set("rendering/environment/default_environment", "");
+ // File was erased, clear the field.
+ ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
} else {
- //file was erased, notify user.
+ // File was erased, notify user.
ERR_PRINT(RTR("Default Environment as specified in Project Settings (Rendering -> Environment -> Default Environment) could not be loaded."));
}
}
}
}
+#endif // _3D_DISABLED
root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true));
@@ -1478,5 +1440,7 @@ SceneTree::~SceneTree() {
memdelete(root);
}
- if (singleton == this) singleton = nullptr;
+ if (singleton == this) {
+ singleton = nullptr;
+ }
}
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 319b5a7e74..19331c1906 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCENE_MAIN_LOOP_H
-#define SCENE_MAIN_LOOP_H
+#ifndef SCENE_TREE_H
+#define SCENE_TREE_H
-#include "core/io/multiplayer_api.h"
+#include "core/multiplayer/multiplayer_api.h"
#include "core/os/main_loop.h"
#include "core/os/thread_safe.h"
-#include "core/self_list.h"
+#include "core/templates/self_list.h"
#include "scene/resources/mesh.h"
#include "scene/resources/world_2d.h"
#include "scene/resources/world_3d.h"
@@ -47,22 +47,27 @@ 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;
- bool process_pause;
+ double time_left = 0.0;
+ bool process_always = true;
+ bool ignore_time_scale = false;
protected:
static void _bind_methods();
public:
- void set_time_left(float p_time);
- float get_time_left() const;
+ void set_time_left(double p_time);
+ double get_time_left() const;
- void set_pause_mode_process(bool p_pause_mode_process);
- bool is_pause_mode_process();
+ void set_process_always(bool p_process_always);
+ bool is_process_always();
+
+ void set_ignore_time_scale(bool p_ignore);
+ bool is_ignore_time_scale();
void release_connections();
@@ -70,7 +75,6 @@ public:
};
class SceneTree : public MainLoop {
-
_THREAD_SAFE_CLASS_
GDCLASS(SceneTree, MainLoop);
@@ -80,60 +84,55 @@ public:
private:
struct Group {
-
Vector<Node *> nodes;
- //uint64_t last_tree_version;
- bool changed;
- Group() { changed = false; };
+ bool changed = false;
};
- Window *root;
+ Window *root = nullptr;
- uint64_t tree_version;
- float physics_process_time;
- float idle_process_time;
- bool accept_quit;
- bool quit_on_go_back;
+ uint64_t tree_version = 1;
+ double physics_process_time = 1.0;
+ double process_time = 1.0;
+ bool accept_quit = true;
+ bool quit_on_go_back = true;
#ifdef DEBUG_ENABLED
- bool debug_collisions_hint;
- bool debug_navigation_hint;
+ bool debug_collisions_hint = false;
+ bool debug_navigation_hint = false;
#endif
- bool pause;
- int root_lock;
+ bool paused = false;
+ int root_lock = 0;
Map<StringName, Group> group_map;
- bool _quit;
- bool initialized;
+ bool _quit = false;
+ bool initialized = false;
- StringName tree_changed_name;
- StringName node_added_name;
- StringName node_removed_name;
- StringName node_renamed_name;
+ StringName tree_changed_name = "tree_changed";
+ StringName node_added_name = "node_added";
+ StringName node_removed_name = "node_removed";
+ StringName node_renamed_name = "node_renamed";
- int64_t current_frame;
- int64_t current_event;
- int node_count;
+ int64_t current_frame = 0;
+ int node_count = 0;
#ifdef TOOLS_ENABLED
Node *edited_scene_root;
#endif
struct UGCall {
-
StringName group;
StringName call;
bool operator<(const UGCall &p_with) const { return group == p_with.group ? call < p_with.call : group < p_with.group; }
};
- //safety for when a node is deleted while a group is being called
- int call_lock;
- Set<Node *> call_skip; //skip erased nodes
+ // Safety for when a node is deleted while a group is being called.
+ int call_lock = 0;
+ Set<Node *> call_skip; // Skip erased nodes.
List<ObjectID> delete_queue;
Map<UGCall, Vector<Variant>> unique_group_calls;
- bool ugc_locked;
+ bool ugc_locked = false;
void _flush_ugc();
_FORCE_INLINE_ void _update_group_order(Group &g, bool p_use_priority = false);
@@ -157,18 +156,12 @@ 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;
-
- void _network_peer_connected(int p_id);
- void _network_peer_disconnected(int p_id);
-
- void _connected_to_server();
- void _connection_failed();
- void _server_disconnected();
+ bool multiplayer_poll = true;
static SceneTree *singleton;
friend class Node;
@@ -177,6 +170,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);
@@ -187,7 +181,7 @@ private:
Variant _call_group(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
void _flush_delete_queue();
- //optimization
+ // Optimization.
friend class CanvasItem;
friend class Node3D;
friend class Viewport;
@@ -210,8 +204,14 @@ private:
void _main_window_close();
void _main_window_go_back();
+ enum CallInputType {
+ CALL_INPUT_TYPE_INPUT,
+ CALL_INPUT_TYPE_UNHANDLED_INPUT,
+ CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT,
+ };
+
//used by viewport
- void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport);
+ void _call_input_pause(const StringName &p_group, CallInputType p_call_type, const Ref<InputEvent> &p_input, Viewport *p_viewport);
protected:
void _notification(int p_notification);
@@ -227,7 +227,6 @@ public:
GROUP_CALL_REVERSE = 1,
GROUP_CALL_REALTIME = 2,
GROUP_CALL_UNIQUE = 4,
- GROUP_CALL_MULTILEVEL = 8,
};
_FORCE_INLINE_ Window *get_root() const { return root; }
@@ -242,20 +241,20 @@ public:
void flush_transform_notifications();
- virtual void init();
+ virtual void initialize() override;
- virtual bool iteration(float p_time);
- virtual bool idle(float p_time);
+ virtual bool physics_process(double p_time) override;
+ virtual bool process(double p_time) override;
- virtual void finish();
+ virtual void finalize() override;
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_idle_process_time() const { return idle_process_time; }
+ _FORCE_INLINE_ double get_physics_process_time() const { return physics_process_time; }
+ _FORCE_INLINE_ double get_process_time() const { return process_time; }
#ifdef TOOLS_ENABLED
bool is_node_being_edited(const Node *p_node) const;
@@ -303,13 +302,13 @@ public:
int get_collision_debug_contact_count() { return collision_debug_contacts; }
int64_t get_frame() const;
- int64_t get_event_count() const;
int get_node_count() const;
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);
@@ -324,14 +323,16 @@ public:
Error change_scene_to(const Ref<PackedScene> &p_scene);
Error reload_current_scene();
- Ref<SceneTreeTimer> create_timer(float p_delay_sec, bool p_process_pause = true);
+ Ref<SceneTreeTimer> create_timer(double 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);
static SceneTree *get_singleton() { return singleton; }
- void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
+ void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
//network API
@@ -339,16 +340,6 @@ public:
void set_multiplayer_poll_enabled(bool p_enabled);
bool is_multiplayer_poll_enabled() const;
void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
- void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer);
- Ref<NetworkedMultiplayerPeer> get_network_peer() const;
- bool is_network_server() const;
- bool has_network_peer() const;
- int get_network_unique_id() const;
- Vector<int> get_network_connected_peers() const;
- int get_rpc_sender_id() const;
-
- void set_refuse_new_network_connections(bool p_refuse);
- bool is_refusing_new_network_connections() const;
static void add_idle_callback(IdleCallback p_callback);
@@ -360,4 +351,4 @@ public:
VARIANT_ENUM_CAST(SceneTree::GroupCallFlags);
-#endif
+#endif // SCENE_TREE_H
diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
index 13582cf655..9477e300d1 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -1,11 +1,39 @@
+/*************************************************************************/
+/* shader_globals_override.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
#include "shader_globals_override.h"
-#include "core/core_string_names.h"
-#include "scene/main/window.h"
+#include "scene/3d/node_3d.h"
#include "scene/scene_string_names.h"
StringName *ShaderGlobalsOverride::_remap(const StringName &p_name) const {
-
StringName *r = param_remaps.getptr(p_name);
if (!r) {
//not cached, do caching
@@ -19,8 +47,8 @@ StringName *ShaderGlobalsOverride::_remap(const StringName &p_name) const {
return r;
}
-bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_value) {
+bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_value) {
StringName *r = _remap(p_name);
if (r) {
@@ -34,7 +62,12 @@ bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_valu
if (o) {
o->override = p_value;
if (active) {
- RS::get_singleton()->global_variable_set_override(*r, p_value);
+ if (o->override.get_type() == Variant::OBJECT) {
+ RID tex_rid = p_value;
+ RS::get_singleton()->global_variable_set_override(*r, tex_rid);
+ } else {
+ RS::get_singleton()->global_variable_set_override(*r, p_value);
+ }
}
o->in_use = p_value.get_type() != Variant::NIL;
return true;
@@ -45,7 +78,6 @@ bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_valu
}
bool ShaderGlobalsOverride::_get(const StringName &p_name, Variant &r_ret) const {
-
StringName *r = _remap(p_name);
if (r) {
@@ -60,7 +92,6 @@ bool ShaderGlobalsOverride::_get(const StringName &p_name, Variant &r_ret) const
}
void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const {
-
Vector<StringName> variables;
variables = RS::get_singleton()->global_variable_get_list();
for (int i = 0; i < variables.size(); i++) {
@@ -142,7 +173,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;
@@ -168,7 +199,6 @@ void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const
pinfo.hint_string = "Cubemap";
} break;
default: {
-
} break;
}
@@ -176,7 +206,7 @@ void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const
Override o;
o.in_use = false;
Callable::CallError ce;
- o.override = Variant::construct(pinfo.type, NULL, 0, ce);
+ Variant::construct(pinfo.type, o.override, nullptr, 0, ce);
overrides[variables[i]] = o;
}
@@ -191,7 +221,6 @@ void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const
}
void ShaderGlobalsOverride::_activate() {
-
List<Node *> nodes;
get_tree()->get_nodes_in_group(SceneStringNames::get_singleton()->shader_overrides_group_active, &nodes);
if (nodes.size() == 0) {
@@ -203,23 +232,25 @@ 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
}
}
void ShaderGlobalsOverride::_notification(int p_what) {
-
if (p_what == Node3D::NOTIFICATION_ENTER_TREE) {
-
add_to_group(SceneStringNames::get_singleton()->shader_overrides_group);
_activate();
} else if (p_what == Node3D::NOTIFICATION_EXIT_TREE) {
-
if (active) {
//remove overrides
const StringName *K = nullptr;
@@ -238,20 +269,18 @@ void ShaderGlobalsOverride::_notification(int p_what) {
}
}
-String ShaderGlobalsOverride::get_configuration_warning() const {
+TypedArray<String> ShaderGlobalsOverride::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!active) {
- return 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 String();
+ return warnings;
}
void ShaderGlobalsOverride::_bind_methods() {
-
ClassDB::bind_method(D_METHOD("_activate"), &ShaderGlobalsOverride::_activate);
}
-ShaderGlobalsOverride::ShaderGlobalsOverride() {
- active = false;
-}
+ShaderGlobalsOverride::ShaderGlobalsOverride() {}
diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h
index 33d0dc948f..ab4b9de727 100644
--- a/scene/main/shader_globals_override.h
+++ b/scene/main/shader_globals_override.h
@@ -1,10 +1,39 @@
+/*************************************************************************/
+/* shader_globals_override.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
#ifndef SHADER_GLOBALS_OVERRIDE_H
#define SHADER_GLOBALS_OVERRIDE_H
-#include "scene/3d/node_3d.h"
+#include "scene/main/node.h"
class ShaderGlobalsOverride : public Node {
-
GDCLASS(ShaderGlobalsOverride, Node);
struct Override {
@@ -14,7 +43,7 @@ class ShaderGlobalsOverride : public Node {
StringName *_remap(const StringName &p_name) const;
- bool active;
+ bool active = false;
mutable HashMap<StringName, Override> overrides;
mutable HashMap<StringName, StringName> param_remaps;
@@ -29,7 +58,7 @@ protected:
static void _bind_methods();
public:
- String get_configuration_warning() const;
+ TypedArray<String> get_configuration_warnings() const override;
ShaderGlobalsOverride();
};
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index 7c847095e1..9e462eb1c8 100644
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,84 +30,81 @@
#include "timer.h"
-#include "core/engine.h"
-
void Timer::_notification(int p_what) {
-
switch (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
start();
autostart = false;
}
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
- if (timer_process_mode == TIMER_PROCESS_PHYSICS || !is_processing_internal())
+ if (!processing || timer_process_callback == TIMER_PROCESS_PHYSICS || !is_processing_internal()) {
return;
+ }
time_left -= get_process_delta_time();
if (time_left < 0) {
- if (!one_shot)
+ if (!one_shot) {
time_left += wait_time;
- else
+ } else {
stop();
+ }
- emit_signal("timeout");
+ emit_signal(SNAME("timeout"));
}
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- if (timer_process_mode == TIMER_PROCESS_IDLE || !is_physics_processing_internal())
+ if (!processing || timer_process_callback == TIMER_PROCESS_IDLE || !is_physics_processing_internal()) {
return;
+ }
time_left -= get_physics_process_delta_time();
if (time_left < 0) {
- if (!one_shot)
+ if (!one_shot) {
time_left += wait_time;
- else
+ } else {
stop();
- emit_signal("timeout");
+ }
+ emit_signal(SNAME("timeout"));
}
} break;
}
}
-void Timer::set_wait_time(float p_time) {
+void Timer::set_wait_time(double p_time) {
ERR_FAIL_COND_MSG(p_time <= 0, "Time should be greater than zero.");
wait_time = p_time;
}
-float Timer::get_wait_time() const {
+double Timer::get_wait_time() const {
return wait_time;
}
void Timer::set_one_shot(bool p_one_shot) {
-
one_shot = p_one_shot;
}
-bool Timer::is_one_shot() const {
+bool Timer::is_one_shot() const {
return one_shot;
}
void Timer::set_autostart(bool p_start) {
-
autostart = p_start;
}
-bool Timer::has_autostart() const {
+bool Timer::has_autostart() const {
return autostart;
}
-void Timer::start(float p_time) {
-
+void Timer::start(double p_time) {
ERR_FAIL_COND_MSG(!is_inside_tree(), "Timer was not added to the SceneTree. Either add it or set autostart to true.");
if (p_time > 0) {
@@ -124,8 +121,9 @@ void Timer::stop() {
}
void Timer::set_paused(bool p_paused) {
- if (paused == p_paused)
+ if (paused == p_paused) {
return;
+ }
paused = p_paused;
_set_process(processing);
@@ -139,17 +137,16 @@ bool Timer::is_stopped() const {
return get_time_left() <= 0;
}
-float Timer::get_time_left() const {
-
+double Timer::get_time_left() const {
return time_left > 0 ? time_left : 0;
}
-void Timer::set_timer_process_mode(TimerProcessMode p_mode) {
-
- if (timer_process_mode == p_mode)
+void Timer::set_timer_process_callback(TimerProcessCallback p_callback) {
+ if (timer_process_callback == p_callback) {
return;
+ }
- switch (timer_process_mode) {
+ switch (timer_process_callback) {
case TIMER_PROCESS_PHYSICS:
if (is_physics_processing_internal()) {
set_physics_process_internal(false);
@@ -163,24 +160,26 @@ void Timer::set_timer_process_mode(TimerProcessMode p_mode) {
}
break;
}
- timer_process_mode = p_mode;
+ timer_process_callback = p_callback;
}
-Timer::TimerProcessMode Timer::get_timer_process_mode() const {
-
- return timer_process_mode;
+Timer::TimerProcessCallback Timer::get_timer_process_callback() const {
+ return timer_process_callback;
}
void Timer::_set_process(bool p_process, bool p_force) {
- switch (timer_process_mode) {
- case TIMER_PROCESS_PHYSICS: set_physics_process_internal(p_process && !paused); break;
- case TIMER_PROCESS_IDLE: set_process_internal(p_process && !paused); break;
+ switch (timer_process_callback) {
+ case TIMER_PROCESS_PHYSICS:
+ set_physics_process_internal(p_process && !paused);
+ break;
+ case TIMER_PROCESS_IDLE:
+ set_process_internal(p_process && !paused);
+ break;
}
processing = p_process;
}
void Timer::_bind_methods() {
-
ClassDB::bind_method(D_METHOD("set_wait_time", "time_sec"), &Timer::set_wait_time);
ClassDB::bind_method(D_METHOD("get_wait_time"), &Timer::get_wait_time);
@@ -200,28 +199,20 @@ void Timer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_time_left"), &Timer::get_time_left);
- ClassDB::bind_method(D_METHOD("set_timer_process_mode", "mode"), &Timer::set_timer_process_mode);
- ClassDB::bind_method(D_METHOD("get_timer_process_mode"), &Timer::get_timer_process_mode);
+ ClassDB::bind_method(D_METHOD("set_timer_process_callback", "callback"), &Timer::set_timer_process_callback);
+ ClassDB::bind_method(D_METHOD("get_timer_process_callback"), &Timer::get_timer_process_callback);
ADD_SIGNAL(MethodInfo("timeout"));
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_mode", "get_timer_process_mode");
- 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::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_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);
}
-Timer::Timer() {
- timer_process_mode = TIMER_PROCESS_IDLE;
- autostart = false;
- wait_time = 1;
- one_shot = false;
- time_left = -1;
- processing = false;
- paused = false;
-}
+Timer::Timer() {}
diff --git a/scene/main/timer.h b/scene/main/timer.h
index 044566738e..2b9faddcb9 100644
--- a/scene/main/timer.h
+++ b/scene/main/timer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,29 +34,28 @@
#include "scene/main/node.h"
class Timer : public Node {
-
GDCLASS(Timer, Node);
- float wait_time;
- bool one_shot;
- bool autostart;
- bool processing;
- bool paused;
+ double wait_time = 1.0;
+ bool one_shot = false;
+ bool autostart = false;
+ bool processing = false;
+ bool paused = false;
- double time_left;
+ double time_left = -1.0;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
- enum TimerProcessMode {
+ enum TimerProcessCallback {
TIMER_PROCESS_PHYSICS,
TIMER_PROCESS_IDLE,
};
- void set_wait_time(float p_time);
- float get_wait_time() const;
+ void set_wait_time(double p_time);
+ double get_wait_time() const;
void set_one_shot(bool p_one_shot);
bool is_one_shot() const;
@@ -64,7 +63,7 @@ public:
void set_autostart(bool p_start);
bool has_autostart() const;
- void start(float p_time = -1);
+ void start(double p_time = -1);
void stop();
void set_paused(bool p_paused);
@@ -72,17 +71,17 @@ public:
bool is_stopped() const;
- float get_time_left() const;
+ double get_time_left() const;
- void set_timer_process_mode(TimerProcessMode p_mode);
- TimerProcessMode get_timer_process_mode() const;
+ void set_timer_process_callback(TimerProcessCallback p_callback);
+ TimerProcessCallback get_timer_process_callback() const;
Timer();
private:
- TimerProcessMode timer_process_mode;
+ TimerProcessCallback timer_process_callback = TIMER_PROCESS_IDLE;
void _set_process(bool p_process, bool p_force = false);
};
-VARIANT_ENUM_CAST(Timer::TimerProcessMode);
+VARIANT_ENUM_CAST(Timer::TimerProcessCallback);
#endif // TIMER_H
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 51dd22db81..fb86d37280 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,31 +32,31 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
-#include "core/input/input_filter.h"
-#include "core/os/os.h"
-#include "core/project_settings.h"
+#include "core/object/message_queue.h"
+#include "core/string/translation.h"
+#include "core/templates/pair.h"
+#include "scene/2d/camera_2d.h"
#include "scene/2d/collision_object_2d.h"
+#include "scene/2d/listener_2d.h"
+#ifndef _3D_DISABLED
#include "scene/3d/camera_3d.h"
#include "scene/3d/collision_object_3d.h"
#include "scene/3d/listener_3d.h"
-#include "scene/3d/node_3d.h"
#include "scene/3d/world_environment.h"
+#endif // _3D_DISABLED
#include "scene/gui/control.h"
#include "scene/gui/label.h"
-#include "scene/gui/menu_button.h"
-#include "scene/gui/panel.h"
-#include "scene/gui/panel_container.h"
+#include "scene/gui/popup.h"
#include "scene/gui/popup_menu.h"
#include "scene/main/canvas_layer.h"
-#include "scene/main/timer.h"
#include "scene/main/window.h"
#include "scene/resources/mesh.h"
+#include "scene/resources/text_line.h"
+#include "scene/resources/world_2d.h"
#include "scene/scene_string_names.h"
-#include "servers/display_server.h"
-#include "servers/physics_server_2d.h"
+#include "servers/audio_server.h"
void ViewportTexture::setup_local_to_scene() {
-
if (vp) {
vp->viewport_textures.erase(this);
}
@@ -81,15 +81,15 @@ void ViewportTexture::setup_local_to_scene() {
RS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid);
RS::get_singleton()->free(proxy_ph);
} else {
- ERR_FAIL_COND(proxy.is_valid()); //should be invalid
+ ERR_FAIL_COND(proxy.is_valid()); // Should be invalid.
proxy = RS::get_singleton()->texture_proxy_create(vp->texture_rid);
}
}
void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) {
-
- if (path == p_path)
+ if (path == p_path) {
return;
+ }
path = p_path;
@@ -99,28 +99,25 @@ void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) {
}
NodePath ViewportTexture::get_viewport_path_in_scene() const {
-
return path;
}
int ViewportTexture::get_width() const {
-
ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it.");
return vp->size.width;
}
-int ViewportTexture::get_height() const {
+int ViewportTexture::get_height() const {
ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it.");
return vp->size.height;
}
-Size2 ViewportTexture::get_size() const {
+Size2 ViewportTexture::get_size() const {
ERR_FAIL_COND_V_MSG(!vp, Size2(), "Viewport Texture must be set to use it.");
return vp->size;
}
-RID ViewportTexture::get_rid() const {
- //ERR_FAIL_COND_V_MSG(!vp, RID(), "Viewport Texture must be set to use it.");
+RID ViewportTexture::get_rid() const {
if (proxy.is_null()) {
proxy_ph = RS::get_singleton()->texture_2d_placeholder_create();
proxy = RS::get_singleton()->texture_proxy_create(proxy_ph);
@@ -129,17 +126,15 @@ RID ViewportTexture::get_rid() const {
}
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);
}
void ViewportTexture::_bind_methods() {
-
ClassDB::bind_method(D_METHOD("set_viewport_path_in_scene", "path"), &ViewportTexture::set_viewport_path_in_scene);
ClassDB::bind_method(D_METHOD("get_viewport_path_in_scene"), &ViewportTexture::get_viewport_path_in_scene);
@@ -147,13 +142,10 @@ void ViewportTexture::_bind_methods() {
}
ViewportTexture::ViewportTexture() {
-
- vp = nullptr;
set_local_to_scene(true);
}
ViewportTexture::~ViewportTexture() {
-
if (vp) {
vp->viewport_textures.erase(this);
}
@@ -168,84 +160,34 @@ ViewportTexture::~ViewportTexture() {
/////////////////////////////////////
-class TooltipPanel : public PopupPanel {
+// Aliases used to provide custom styles to tooltips in the default
+// theme and editor theme.
+// TooltipPanel is also used for custom tooltips, while TooltipLabel
+// is only relevant for default tooltips.
+class TooltipPanel : public PopupPanel {
GDCLASS(TooltipPanel, PopupPanel);
public:
- TooltipPanel(){};
+ TooltipPanel() {}
};
class TooltipLabel : public Label {
-
GDCLASS(TooltipLabel, Label);
public:
- TooltipLabel(){};
+ TooltipLabel() {}
};
-Viewport::GUI::GUI() {
-
- embed_subwindows_hint = false;
- embedding_subwindows = false;
-
- dragging = false;
- mouse_focus = nullptr;
- forced_mouse_focus = false;
- mouse_click_grabber = nullptr;
- mouse_focus_mask = 0;
- key_focus = nullptr;
- mouse_over = nullptr;
- drag_mouse_over = nullptr;
-
- tooltip = nullptr;
- tooltip_popup = nullptr;
- tooltip_label = nullptr;
-}
-
/////////////////////////////////////
-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()->_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();
- ObjectID id = p_object->get_instance_id();
-
- //avoid sending the fake event unnecessarily if nothing really changed in the context
- if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) {
- Ref<InputEventMouseMotion> mm = p_input_event;
- if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
- return; //discarded
- }
- }
- p_object->_input_event(camera, p_input_event, p_pos, p_normal, p_shape);
- physics_last_object_transform = object_transform;
- physics_last_camera_transform = camera_transform;
- physics_last_id = id;
-}
-
void Viewport::_sub_window_update_order() {
-
for (int i = 0; i < gui.sub_windows.size(); i++) {
RS::get_singleton()->canvas_item_set_draw_index(gui.sub_windows[i].canvas_item, i);
}
}
void Viewport::_sub_window_register(Window *p_window) {
-
ERR_FAIL_COND(!is_inside_tree());
for (int i = 0; i < gui.sub_windows.size(); i++) {
ERR_FAIL_COND(gui.sub_windows[i].window == p_window);
@@ -268,7 +210,6 @@ void Viewport::_sub_window_register(Window *p_window) {
}
void Viewport::_sub_window_update(Window *p_window) {
-
int index = -1;
for (int i = 0; i < gui.sub_windows.size(); i++) {
if (gui.sub_windows[i].window == p_window) {
@@ -287,25 +228,32 @@ void Viewport::_sub_window_update(Window *p_window) {
Rect2i r = Rect2i(p_window->get_position(), sw.window->get_size());
if (!p_window->get_flag(Window::FLAG_BORDERLESS)) {
- Ref<StyleBox> panel = p_window->get_theme_stylebox("panel_window");
+ Ref<StyleBox> panel = p_window->get_theme_stylebox(SNAME("embedded_border"));
panel->draw(sw.canvas_item, r);
// Draw the title bar text.
- Ref<Font> title_font = p_window->get_theme_font("title_font");
- Color title_color = p_window->get_theme_color("title_color");
- int title_height = p_window->get_theme_constant("title_height");
- int font_height = title_font->get_height() - title_font->get_descent() * 2;
- int x = (r.size.width - title_font->get_string_size(p_window->get_title()).x) / 2;
- int y = (-title_height + font_height) / 2;
-
- int close_h_ofs = p_window->get_theme_constant("close_h_ofs");
- int close_v_ofs = p_window->get_theme_constant("close_v_ofs");
-
- title_font->draw(sw.canvas_item, r.position + Point2(x, y), p_window->get_title(), title_color, r.size.width - panel->get_minimum_size().x - close_h_ofs);
-
- bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside;
+ Ref<Font> title_font = p_window->get_theme_font(SNAME("title_font"));
+ int font_size = p_window->get_theme_font_size(SNAME("title_font_size"));
+ Color title_color = p_window->get_theme_color(SNAME("title_color"));
+ int title_height = p_window->get_theme_constant(SNAME("title_height"));
+ int close_h_ofs = p_window->get_theme_constant(SNAME("close_h_ofs"));
+ int close_v_ofs = p_window->get_theme_constant(SNAME("close_v_ofs"));
+
+ TextLine title_text = TextLine(p_window->atr(p_window->get_title()), title_font, font_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
+ title_text.set_width(r.size.width - panel->get_minimum_size().x - close_h_ofs);
+ title_text.set_direction(p_window->is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
+ int x = (r.size.width - title_text.get_size().x) / 2;
+ int y = (-title_height - title_text.get_size().y) / 2;
+
+ Color font_outline_color = p_window->get_theme_color(SNAME("title_outline_modulate"));
+ int outline_size = p_window->get_theme_constant(SNAME("title_outline_size"));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ title_text.draw_outline(sw.canvas_item, r.position + Point2(x, y), outline_size, font_outline_color);
+ }
+ title_text.draw(sw.canvas_item, r.position + Point2(x, y), title_color);
- Ref<Texture2D> close_icon = p_window->get_theme_icon(hl ? "close_highlight" : "close");
+ bool pressed = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside;
+ Ref<Texture2D> close_icon = p_window->get_theme_icon(pressed ? "close_pressed" : "close");
close_icon->draw(sw.canvas_item, r.position + Vector2(r.size.width - close_h_ofs, -close_v_ofs));
}
@@ -313,9 +261,8 @@ void Viewport::_sub_window_update(Window *p_window) {
}
void Viewport::_sub_window_grab_focus(Window *p_window) {
-
if (p_window == nullptr) {
- //release current focus
+ // Release current focus.
if (gui.subwindow_focused) {
gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
gui.subwindow_focused = nullptr;
@@ -341,18 +288,18 @@ void Viewport::_sub_window_grab_focus(Window *p_window) {
ERR_FAIL_COND(index == -1);
if (p_window->get_flag(Window::FLAG_NO_FOCUS)) {
- //can only move to foreground, but no focus granted
+ // Can only move to foreground, but no focus granted.
SubWindow sw = gui.sub_windows[index];
gui.sub_windows.remove(index);
gui.sub_windows.push_back(sw);
index = gui.sub_windows.size() - 1;
_sub_window_update_order();
- return; //i guess not...
+ return;
}
if (gui.subwindow_focused) {
if (gui.subwindow_focused == p_window) {
- return; //nothing to do
+ return; // Nothing to do.
}
gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
@@ -369,7 +316,7 @@ void Viewport::_sub_window_grab_focus(Window *p_window) {
gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
- { //move to foreground
+ { // Move to foreground.
SubWindow sw = gui.sub_windows[index];
gui.sub_windows.remove(index);
gui.sub_windows.push_back(sw);
@@ -385,7 +332,6 @@ void Viewport::_sub_window_grab_focus(Window *p_window) {
}
void Viewport::_sub_window_remove(Window *p_window) {
-
for (int i = 0; i < gui.sub_windows.size(); i++) {
if (gui.sub_windows[i].window == p_window) {
RS::get_singleton()->free(gui.sub_windows[i].canvas_item);
@@ -407,7 +353,6 @@ void Viewport::_sub_window_remove(Window *p_window) {
gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
if (parent_visible && parent_visible != this) {
-
gui.subwindow_focused = parent_visible;
gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
} else {
@@ -422,33 +367,9 @@ void Viewport::_sub_window_remove(Window *p_window) {
RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID());
}
-void Viewport::_own_world_changed() {
- ERR_FAIL_COND(world.is_null());
- ERR_FAIL_COND(own_world.is_null());
-
- if (is_inside_tree()) {
- _propagate_exit_world(this);
- }
-
- own_world = world->duplicate();
-
- if (is_inside_tree()) {
- _propagate_enter_world(this);
- }
-
- if (is_inside_tree()) {
- RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
- }
-
- _update_listener();
-}
-
void Viewport::_notification(int p_what) {
-
switch (p_what) {
-
case NOTIFICATION_ENTER_TREE: {
-
gui.embedding_subwindows = gui.embed_subwindows_hint;
if (get_parent()) {
@@ -459,73 +380,64 @@ void Viewport::_notification(int p_what) {
}
current_canvas = find_world_2d()->get_canvas();
- RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
-
- _update_listener();
_update_listener_2d();
-
- find_world_2d()->_register_viewport(this, Rect2());
+#ifndef _3D_DISABLED
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
+ _update_listener_3d();
+#endif // _3D_DISABLED
add_to_group("_viewports");
if (get_tree()->is_debugging_collisions_hint()) {
- //2D
PhysicsServer2D::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(), get_tree()->get_collision_debug_contact_count());
contact_2d_debug = RenderingServer::get_singleton()->canvas_item_create();
RenderingServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, find_world_2d()->get_canvas());
- //3D
- PhysicsServer3D::get_singleton()->space_set_debug_contacts(find_world()->get_space(), get_tree()->get_collision_debug_contact_count());
+#ifndef _3D_DISABLED
+ PhysicsServer3D::get_singleton()->space_set_debug_contacts(find_world_3d()->get_space(), get_tree()->get_collision_debug_contact_count());
contact_3d_debug_multimesh = RenderingServer::get_singleton()->multimesh_create();
- RenderingServer::get_singleton()->multimesh_allocate(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, true);
+ RenderingServer::get_singleton()->multimesh_allocate_data(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, true);
RenderingServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, 0);
RenderingServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh, get_tree()->get_debug_contact_mesh()->get_rid());
contact_3d_debug_instance = RenderingServer::get_singleton()->instance_create();
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()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world_3d()->get_scenario());
//RenderingServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, RS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true);
+#endif // _3D_DISABLED
}
} break;
case NOTIFICATION_READY: {
#ifndef _3D_DISABLED
- if (listeners.size() && !listener) {
+ if (listener_3d_set.size() && !listener_3d) {
Listener3D *first = nullptr;
- for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) {
-
+ for (Set<Listener3D *>::Element *E = listener_3d_set.front(); E; E = E->next()) {
if (first == nullptr || first->is_greater_than(E->get())) {
first = E->get();
}
}
- if (first)
+ if (first) {
first->make_current();
+ }
}
- if (cameras.size() && !camera) {
- //there are cameras but no current camera, pick first in tree and make it current
+ if (camera_3d_set.size() && !camera_3d) {
+ // There are cameras but no current camera, pick first in tree and make it current.
Camera3D *first = nullptr;
- for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
-
+ for (Set<Camera3D *>::Element *E = camera_3d_set.front(); E; E = E->next()) {
if (first == nullptr || first->is_greater_than(E->get())) {
first = E->get();
}
}
- if (first)
+ if (first) {
first->make_current();
+ }
}
-#endif
-
- // Enable processing for tooltips, collision debugging, physics object picking, etc.
- set_process_internal(true);
- set_physics_process_internal(true);
-
+#endif // _3D_DISABLED
} break;
case NOTIFICATION_EXIT_TREE: {
-
_gui_cancel_tooltip();
- 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);
@@ -542,25 +454,13 @@ void Viewport::_notification(int p_what) {
}
remove_from_group("_viewports");
+ set_physics_process_internal(false);
RS::get_singleton()->viewport_set_active(viewport, false);
RenderingServer::get_singleton()->viewport_set_parent_viewport(viewport, RID());
-
- } break;
- case NOTIFICATION_INTERNAL_PROCESS: {
-
- if (gui.tooltip_timer >= 0) {
- gui.tooltip_timer -= get_process_delta_time();
- if (gui.tooltip_timer < 0) {
- _gui_show_tooltip();
- }
- }
-
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
-
if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) {
-
RenderingServer::get_singleton()->canvas_item_clear(contact_2d_debug);
RenderingServer::get_singleton()->canvas_item_set_draw_index(contact_2d_debug, 0xFFFFF); //very high index
@@ -569,320 +469,312 @@ void Viewport::_notification(int p_what) {
Color ccol = get_tree()->get_debug_collision_contact_color();
for (int i = 0; i < point_count; i++) {
-
RenderingServer::get_singleton()->canvas_item_add_rect(contact_2d_debug, Rect2(points[i] - Vector2(2, 2), Vector2(5, 5)), ccol);
}
}
-
+#ifndef _3D_DISABLED
if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) {
-
- Vector<Vector3> points = PhysicsServer3D::get_singleton()->space_get_contacts(find_world()->get_space());
- int point_count = PhysicsServer3D::get_singleton()->space_get_contact_count(find_world()->get_space());
+ Vector<Vector3> points = PhysicsServer3D::get_singleton()->space_get_contacts(find_world_3d()->get_space());
+ int point_count = PhysicsServer3D::get_singleton()->space_get_contact_count(find_world_3d()->get_space());
RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
- }
- if (physics_object_picking && (to_screen_rect == Rect2i() || InputFilter::get_singleton()->get_mouse_mode() != InputFilter::MOUSE_MODE_CAPTURED)) {
-
-#ifndef _3D_DISABLED
- Vector2 last_pos(1e20, 1e20);
- CollisionObject3D *last_object = nullptr;
- ObjectID last_id;
-#endif
- PhysicsDirectSpaceState3D::RayResult result;
- PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
-
- if (physics_has_last_mousepos) {
- // if no mouse event exists, create a motion one. This is necessary because objects or camera may have moved.
- // while this extra event is sent, it is checked if both camera and last object and last ID did not move. If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame
- bool has_mouse_event = false;
- for (List<Ref<InputEvent>>::Element *E = physics_picking_events.front(); E; E = E->next()) {
- Ref<InputEventMouse> m = E->get();
- if (m.is_valid()) {
- has_mouse_event = true;
- break;
- }
- }
-
- if (!has_mouse_event) {
- Ref<InputEventMouseMotion> mm;
- mm.instance();
-
- 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_button_mask(physics_last_mouse_state.mouse_mask);
- physics_picking_events.push_back(mm);
- }
+ for (int i = 0; i < point_count; i++) {
+ Transform3D point_transform;
+ point_transform.origin = points[i];
+ RS::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh, i, point_transform);
}
+ }
+#endif // _3D_DISABLED
+ } break;
+ case NOTIFICATION_WM_MOUSE_EXIT: {
+ _drop_physics_mouseover();
- while (physics_picking_events.size()) {
+ // Unlike on loss of focus (NOTIFICATION_WM_WINDOW_FOCUS_OUT), do not
+ // drop the gui mouseover here, as a scrollbar may be dragged while the
+ // mouse is outside the window (without the window having lost focus).
+ // See bug #39634
+ } break;
+ case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
+ _drop_physics_mouseover();
- Ref<InputEvent> ev = physics_picking_events.front()->get();
- physics_picking_events.pop_front();
+ if (gui.mouse_focus && !gui.forced_mouse_focus) {
+ _drop_mouse_focus();
+ }
+ } break;
+ }
+}
- Vector2 pos;
- bool is_mouse = false;
+void Viewport::_process_picking() {
+ if (!is_inside_tree()) {
+ return;
+ }
+ if (!physics_object_picking) {
+ return;
+ }
+ if (to_screen_rect != Rect2i() && Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {
+ return;
+ }
- Ref<InputEventMouseMotion> mm = ev;
+ _drop_physics_mouseover(true);
- if (mm.is_valid()) {
+ PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
- pos = mm->get_position();
- is_mouse = true;
+ if (physics_has_last_mousepos) {
+ // If no mouse event exists, create a motion one. This is necessary because objects or camera may have moved.
+ // While this extra event is sent, it is checked if both camera and last object and last ID did not move.
+ // If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame.
+ bool has_mouse_event = false;
+ for (const Ref<InputEvent> &m : physics_picking_events) {
+ if (m.is_valid()) {
+ has_mouse_event = true;
+ break;
+ }
+ }
- 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.mouse_mask = mm->get_button_mask();
- }
+ if (!has_mouse_event) {
+ Ref<InputEventMouseMotion> mm;
+ 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_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);
+ }
+ }
- Ref<InputEventMouseButton> mb = ev;
+ while (physics_picking_events.size()) {
+ Ref<InputEvent> ev = physics_picking_events.front()->get();
+ physics_picking_events.pop_front();
- if (mb.is_valid()) {
+ Vector2 pos;
+ bool is_mouse = false;
- pos = mb->get_position();
- is_mouse = true;
+ Ref<InputEventMouseMotion> mm = ev;
- 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();
+ if (mm.is_valid()) {
+ pos = mm->get_position();
+ is_mouse = true;
+
+ physics_has_last_mousepos = true;
+ physics_last_mousepos = pos;
+ 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();
+ }
- if (mb->is_pressed()) {
- physics_last_mouse_state.mouse_mask |= (1 << (mb->get_button_index() - 1));
- } else {
- physics_last_mouse_state.mouse_mask &= ~(1 << (mb->get_button_index() - 1));
+ Ref<InputEventMouseButton> mb = ev;
- // 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) {
- physics_has_last_mousepos = false;
- }
- }
- }
+ if (mb.is_valid()) {
+ pos = mb->get_position();
+ is_mouse = true;
- 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();
- continue;
- }
+ physics_has_last_mousepos = true;
+ physics_last_mousepos = pos;
+ 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();
- Ref<InputEventScreenDrag> sd = ev;
+ if (mb->is_pressed()) {
+ physics_last_mouse_state.mouse_mask |= (MouseButton)(1 << (mb->get_button_index() - 1));
+ } else {
+ physics_last_mouse_state.mouse_mask &= (MouseButton) ~(1 << (mb->get_button_index() - 1));
- if (sd.is_valid()) {
- pos = sd->get_position();
- }
+ // 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) {
+ physics_has_last_mousepos = false;
+ }
+ }
+ }
- Ref<InputEventScreenTouch> st = ev;
+ Ref<InputEventKey> k = ev;
+ if (k.is_valid()) {
+ // Only for mask.
+ physics_last_mouse_state.alt = k->is_alt_pressed();
+ physics_last_mouse_state.shift = k->is_shift_pressed();
+ physics_last_mouse_state.control = k->is_ctrl_pressed();
+ physics_last_mouse_state.meta = k->is_meta_pressed();
+ continue;
+ }
- if (st.is_valid()) {
- pos = st->get_position();
- }
+ Ref<InputEventScreenDrag> sd = ev;
- if (ss2d) {
- //send to 2D
+ if (sd.is_valid()) {
+ pos = sd->get_position();
+ }
- uint64_t frame = get_tree()->get_frame();
+ Ref<InputEventScreenTouch> st = ev;
- PhysicsDirectSpaceState2D::ShapeResult res[64];
- for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) {
- Transform2D canvas_transform;
- ObjectID canvas_layer_id;
- if (E->get()) {
- // A descendant CanvasLayer
- canvas_transform = E->get()->get_transform();
- canvas_layer_id = E->get()->get_instance_id();
- } else {
- // This Viewport's builtin canvas
- canvas_transform = get_canvas_transform();
- canvas_layer_id = ObjectID();
- }
+ if (st.is_valid()) {
+ pos = st->get_position();
+ }
- Vector2 point = canvas_transform.affine_inverse().xform(pos);
-
- int rc = ss2d->intersect_point_on_canvas(point, canvas_layer_id, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
- for (int i = 0; i < rc; i++) {
-
- if (res[i].collider_id.is_valid() && res[i].collider) {
- CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
- if (co) {
- bool send_event = true;
- if (is_mouse) {
- Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id);
-
- if (!F) {
- physics_2d_mouseover.insert(res[i].collider_id, frame);
- co->_mouse_enter();
- } else {
- F->get() = frame;
- // It was already hovered, so don't send the event if it's faked
- if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
- send_event = false;
- }
- }
- }
-
- if (send_event) {
- co->_input_event(this, ev, res[i].shape);
- }
- }
- }
- }
- }
+ if (ss2d) {
+ // Send to 2D.
- if (is_mouse) {
- List<Map<ObjectID, uint64_t>::Element *> to_erase;
+ uint64_t frame = get_tree()->get_frame();
- 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) {
+ PhysicsDirectSpaceState2D::ShapeResult res[64];
+ for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) {
+ Transform2D canvas_transform;
+ ObjectID canvas_layer_id;
+ if (E->get()) {
+ // A descendant CanvasLayer.
+ canvas_transform = E->get()->get_transform();
+ canvas_layer_id = E->get()->get_instance_id();
+ } else {
+ // This Viewport's builtin canvas.
+ canvas_transform = get_canvas_transform();
+ canvas_layer_id = ObjectID();
+ }
- CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
- if (co) {
- co->_mouse_exit();
- }
+ Vector2 point = canvas_transform.affine_inverse().xform(pos);
+
+ int rc = ss2d->intersect_point_on_canvas(point, canvas_layer_id, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
+ for (int i = 0; i < rc; i++) {
+ if (res[i].collider_id.is_valid() && res[i].collider) {
+ CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
+ if (co && co->can_process()) {
+ bool send_event = true;
+ if (is_mouse) {
+ Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id);
+ if (!F) {
+ physics_2d_mouseover.insert(res[i].collider_id, frame);
+ co->_mouse_enter();
+ } else {
+ F->get() = frame;
+ // It was already hovered, so don't send the event if it's faked.
+ if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
+ send_event = false;
}
- to_erase.push_back(E);
+ }
+ 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;
}
}
- while (to_erase.size()) {
- physics_2d_mouseover.erase(to_erase.front()->get());
- to_erase.pop_front();
+ if (send_event) {
+ co->_input_event_call(this, ev, res[i].shape);
}
}
}
+ }
+ }
+
+ if (is_mouse) {
+ _cleanup_mouseover_colliders(false, false, frame);
+ }
+ }
#ifndef _3D_DISABLED
- bool captured = false;
+ Vector2 last_pos(1e20, 1e20);
+ CollisionObject3D *last_object = nullptr;
+ ObjectID last_id;
+ PhysicsDirectSpaceState3D::RayResult result;
+ bool captured = false;
+
+ if (physics_object_capture.is_valid()) {
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture));
+ if (co && camera_3d) {
+ _collision_object_3d_input_event(co, camera_3d, ev, Vector3(), Vector3(), 0);
+ captured = true;
+ if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) {
+ physics_object_capture = ObjectID();
+ }
- if (physics_object_capture.is_valid()) {
+ } else {
+ physics_object_capture = ObjectID();
+ }
+ }
- 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);
- captured = true;
- if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) {
- physics_object_capture = ObjectID();
+ if (captured) {
+ // None.
+ } else if (pos == last_pos) {
+ if (last_id.is_valid()) {
+ if (ObjectDB::get_instance(last_id) && last_object) {
+ // Good, exists.
+ _collision_object_3d_input_event(last_object, camera_3d, ev, result.position, result.normal, result.shape);
+ if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
+ physics_object_capture = last_id;
+ }
+ }
+ }
+ } else {
+ if (camera_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) {
+ bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
+ ObjectID new_collider;
+ if (col) {
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider);
+ if (co && co->can_process()) {
+ _collision_object_3d_input_event(co, camera_3d, ev, result.position, result.normal, result.shape);
+ last_object = co;
+ last_id = result.collider_id;
+ new_collider = last_id;
+ if (co->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
+ physics_object_capture = last_id;
}
-
- } else {
- physics_object_capture = ObjectID();
}
}
- if (captured) {
- //none
- } else if (pos == last_pos) {
-
- if (last_id.is_valid()) {
- if (ObjectDB::get_instance(last_id) && last_object) {
- //good, exists
- _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape);
- if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
- physics_object_capture = last_id;
- }
+ if (is_mouse && new_collider != physics_object_over) {
+ if (physics_object_over.is_valid()) {
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
+ if (co) {
+ co->_mouse_exit();
}
}
- } else {
-
- if (camera) {
-
- Vector3 from = camera->project_ray_origin(pos);
- Vector3 dir = camera->project_ray_normal(pos);
-
- PhysicsDirectSpaceState3D *space = PhysicsServer3D::get_singleton()->space_get_direct_state(find_world()->get_space());
- if (space) {
-
- bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
- ObjectID new_collider;
- if (col) {
- CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider);
- if (co) {
-
- _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape);
- last_object = co;
- last_id = result.collider_id;
- new_collider = last_id;
- if (co->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
- physics_object_capture = last_id;
- }
- }
- }
-
- if (is_mouse && new_collider != physics_object_over) {
-
- if (physics_object_over.is_valid()) {
-
- CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
- if (co) {
- co->_mouse_exit();
- }
- }
-
- if (new_collider.is_valid()) {
-
- CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(new_collider));
- if (co) {
- co->_mouse_enter();
- }
- }
-
- physics_object_over = new_collider;
- }
+ if (new_collider.is_valid()) {
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(new_collider));
+ if (co) {
+ co->_mouse_enter();
}
-
- last_pos = pos;
}
+
+ physics_object_over = new_collider;
}
-#endif
}
- }
-
- } break;
- case NOTIFICATION_WM_MOUSE_EXIT:
- case NOTIFICATION_WM_FOCUS_OUT: {
- _drop_physics_mouseover();
-
- if (gui.mouse_focus && !gui.forced_mouse_focus) {
- _drop_mouse_focus();
+ last_pos = pos;
}
- } break;
+ }
+#endif // _3D_DISABLED
}
}
RID Viewport::get_viewport_rid() const {
-
return viewport;
}
void Viewport::update_canvas_items() {
- if (!is_inside_tree())
+ if (!is_inside_tree()) {
return;
+ }
_update_canvas_items(this);
}
void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated) {
-
- if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_2d_override == size_2d_override && to_screen_rect != p_to_screen_rect)
+ if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_2d_override == size_2d_override && to_screen_rect != p_to_screen_rect) {
return;
+ }
size = p_size;
size_allocated = p_allocated;
@@ -899,21 +791,22 @@ 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 {
return size;
}
+
Size2i Viewport::_get_size_2d_override() const {
return size_2d_override;
}
+
bool Viewport::_is_size_allocated() const {
return size_allocated;
}
Rect2 Viewport::get_visible_rect() const {
-
Rect2 r;
if (size == Size2()) {
@@ -929,48 +822,29 @@ Rect2 Viewport::get_visible_rect() const {
return r;
}
-void Viewport::_update_listener() {
-}
-
void Viewport::_update_listener_2d() {
-
- /*
- if (is_inside_tree() && audio_listener && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree())))
- SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, find_world_2d()->get_sound_space());
- else
- SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, RID());
-*/
-}
-
-void Viewport::set_as_audio_listener(bool p_enable) {
-
- if (p_enable == audio_listener)
- return;
-
- audio_listener = p_enable;
- _update_listener();
-}
-
-bool Viewport::is_audio_listener() const {
-
- return audio_listener;
+ if (AudioServer::get_singleton()) {
+ AudioServer::get_singleton()->notify_listener_changed();
+ }
}
void Viewport::set_as_audio_listener_2d(bool p_enable) {
-
- if (p_enable == audio_listener_2d)
+ if (p_enable == audio_listener_2d) {
return;
+ }
audio_listener_2d = p_enable;
-
_update_listener_2d();
}
bool Viewport::is_audio_listener_2d() const {
-
return audio_listener_2d;
}
+Listener2D *Viewport::get_listener_2d() const {
+ return listener_2d;
+}
+
void Viewport::enable_canvas_transform_override(bool p_enable) {
if (override_canvas_transform == p_enable) {
return;
@@ -1004,7 +878,6 @@ Transform2D Viewport::get_canvas_transform_override() const {
}
void Viewport::set_canvas_transform(const Transform2D &p_transform) {
-
canvas_transform = p_transform;
if (!override_canvas_transform) {
@@ -1013,191 +886,79 @@ void Viewport::set_canvas_transform(const Transform2D &p_transform) {
}
Transform2D Viewport::get_canvas_transform() const {
-
return canvas_transform;
}
void Viewport::_update_global_transform() {
-
Transform2D sxform = stretch_transform * global_canvas_transform;
RenderingServer::get_singleton()->viewport_set_global_canvas_transform(viewport, sxform);
}
void Viewport::set_global_canvas_transform(const Transform2D &p_transform) {
-
global_canvas_transform = p_transform;
_update_global_transform();
}
Transform2D Viewport::get_global_canvas_transform() const {
-
return global_canvas_transform;
}
-void Viewport::_listener_transform_changed_notify() {
-}
-
-void Viewport::_listener_set(Listener3D *p_listener) {
-
-#ifndef _3D_DISABLED
-
- if (listener == p_listener)
- return;
-
- listener = p_listener;
-
- _update_listener();
- _listener_transform_changed_notify();
-#endif
-}
-
-bool Viewport::_listener_add(Listener3D *p_listener) {
-
- listeners.insert(p_listener);
- return listeners.size() == 1;
-}
-
-void Viewport::_listener_remove(Listener3D *p_listener) {
-
- listeners.erase(p_listener);
- if (listener == p_listener) {
- listener = nullptr;
- }
-}
-
-#ifndef _3D_DISABLED
-void Viewport::_listener_make_next_current(Listener3D *p_exclude) {
-
- if (listeners.size() > 0) {
- for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) {
-
- if (p_exclude == E->get())
- continue;
- if (!E->get()->is_inside_tree())
- continue;
- if (listener != nullptr)
- return;
-
- E->get()->make_current();
- }
- } else {
- // Attempt to reset listener to the camera position
- if (camera != nullptr) {
- _update_listener();
- _camera_transform_changed_notify();
- }
- }
+void Viewport::_camera_2d_set(Camera2D *p_camera_2d) {
+ camera_2d = p_camera_2d;
}
-#endif
-
-void Viewport::_camera_transform_changed_notify() {
-#ifndef _3D_DISABLED
-#endif
-}
-
-void Viewport::_camera_set(Camera3D *p_camera) {
-
-#ifndef _3D_DISABLED
-
- if (camera == p_camera)
+void Viewport::_listener_2d_set(Listener2D *p_listener) {
+ if (listener_2d == p_listener) {
return;
-
- if (camera) {
- camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
- }
-
- camera = p_camera;
-
- if (!camera_override) {
- if (camera)
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
- else
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
- }
-
- if (camera) {
- camera->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
- }
-
- _update_listener();
- _camera_transform_changed_notify();
-#endif
-}
-
-bool Viewport::_camera_add(Camera3D *p_camera) {
-
- cameras.insert(p_camera);
- return cameras.size() == 1;
-}
-
-void Viewport::_camera_remove(Camera3D *p_camera) {
-
- cameras.erase(p_camera);
- if (camera == p_camera) {
- camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
- camera = nullptr;
+ } else if (listener_2d) {
+ listener_2d->clear_current();
}
+ listener_2d = p_listener;
}
-#ifndef _3D_DISABLED
-void Viewport::_camera_make_next_current(Camera3D *p_exclude) {
-
- for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
-
- if (p_exclude == E->get())
- continue;
- if (!E->get()->is_inside_tree())
- continue;
- if (camera != nullptr)
- return;
-
- E->get()->make_current();
+void Viewport::_listener_2d_remove(Listener2D *p_listener) {
+ if (listener_2d == p_listener) {
+ listener_2d = nullptr;
}
}
-#endif
void Viewport::_canvas_layer_add(CanvasLayer *p_canvas_layer) {
-
canvas_layers.insert(p_canvas_layer);
}
void Viewport::_canvas_layer_remove(CanvasLayer *p_canvas_layer) {
-
canvas_layers.erase(p_canvas_layer);
}
void Viewport::set_transparent_background(bool p_enable) {
-
transparent_bg = p_enable;
RS::get_singleton()->viewport_set_transparent_background(viewport, p_enable);
}
bool Viewport::has_transparent_background() const {
-
return transparent_bg;
}
void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
- if (world_2d == p_world_2d)
+ if (world_2d == p_world_2d) {
return;
+ }
if (parent && parent->find_world_2d() == p_world_2d) {
- WARN_PRINT("Unable to use parent world as world_2d");
+ WARN_PRINT("Unable to use parent world_2d as world_2d");
return;
}
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())
+ if (p_world_2d.is_valid()) {
world_2d = p_world_2d;
- else {
- WARN_PRINT("Invalid world");
+ } else {
+ WARN_PRINT("Invalid world_2d");
world_2d = Ref<World2D>(memnew(World2D));
}
@@ -1206,237 +967,48 @@ 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());
}
}
Ref<World2D> Viewport::find_world_2d() const {
-
- if (world_2d.is_valid())
+ if (world_2d.is_valid()) {
return world_2d;
- else if (parent)
+ } else if (parent) {
return parent->find_world_2d();
- else
+ } else {
return Ref<World2D>();
-}
-
-void Viewport::_propagate_enter_world(Node *p_node) {
-
- if (p_node != this) {
-
- if (!p_node->is_inside_tree()) //may not have entered scene yet
- return;
-
-#ifndef _3D_DISABLED
- if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
- p_node->notification(Node3D::NOTIFICATION_ENTER_WORLD);
- } else {
-#endif
- Viewport *v = Object::cast_to<Viewport>(p_node);
- if (v) {
-
- if (v->world.is_valid() || v->own_world.is_valid())
- return;
- }
-#ifndef _3D_DISABLED
- }
-#endif
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
-
- _propagate_enter_world(p_node->get_child(i));
}
}
void Viewport::_propagate_viewport_notification(Node *p_node, int p_what) {
-
p_node->notification(p_what);
for (int i = 0; i < p_node->get_child_count(); i++) {
Node *c = p_node->get_child(i);
- if (Object::cast_to<Viewport>(c))
+ if (Object::cast_to<Viewport>(c)) {
continue;
- _propagate_viewport_notification(c, p_what);
- }
-}
-
-void Viewport::_propagate_exit_world(Node *p_node) {
-
- if (p_node != this) {
-
- if (!p_node->is_inside_tree()) //may have exited scene already
- return;
-
-#ifndef _3D_DISABLED
- if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
- p_node->notification(Node3D::NOTIFICATION_EXIT_WORLD);
- } else {
-#endif
- Viewport *v = Object::cast_to<Viewport>(p_node);
- if (v) {
-
- if (v->world.is_valid() || v->own_world.is_valid())
- return;
- }
-#ifndef _3D_DISABLED
}
-#endif
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
-
- _propagate_exit_world(p_node->get_child(i));
- }
-}
-
-void Viewport::set_world(const Ref<World3D> &p_world) {
-
- if (world == p_world)
- return;
-
- if (is_inside_tree())
- _propagate_exit_world(this);
-
- if (own_world.is_valid() && world.is_valid()) {
- world->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
- }
-
- world = p_world;
-
- if (own_world.is_valid()) {
- if (world.is_valid()) {
- own_world = world->duplicate();
- world->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
- } else {
- own_world = Ref<World3D>(memnew(World3D));
- }
- }
-
- if (is_inside_tree())
- _propagate_enter_world(this);
-
- if (is_inside_tree()) {
- RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
+ _propagate_viewport_notification(c, p_what);
}
-
- _update_listener();
-}
-
-Ref<World3D> Viewport::get_world() const {
-
- return world;
}
Ref<World2D> Viewport::get_world_2d() const {
-
return world_2d;
}
-Ref<World3D> Viewport::find_world() const {
-
- if (own_world.is_valid())
- return own_world;
- else if (world.is_valid())
- return world;
- else if (parent)
- return parent->find_world();
- else
- return Ref<World3D>();
-}
-
-Listener3D *Viewport::get_listener() const {
-
- return listener;
-}
-
-Camera3D *Viewport::get_camera() const {
- return camera;
-}
-
-void Viewport::enable_camera_override(bool p_enable) {
-
-#ifndef _3D_DISABLED
- if (p_enable == camera_override) {
- return;
- }
-
- if (p_enable) {
- camera_override.rid = RenderingServer::get_singleton()->camera_create();
- } else {
- RenderingServer::get_singleton()->free(camera_override.rid);
- camera_override.rid = RID();
- }
-
- if (p_enable) {
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid);
- } else if (camera) {
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
- } else {
- RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
- }
-#endif
-}
-
-bool Viewport::is_camera_override_enabled() const {
- return camera_override;
-}
-
-void Viewport::set_camera_override_transform(const Transform &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 {
- if (camera_override) {
- return camera_override.transform;
- }
-
- return Transform();
-}
-
-void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
- if (camera_override) {
- if (camera_override.fov == p_fovy_degrees && camera_override.z_near == p_z_near &&
- camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_PERSPECTIVE)
- return;
-
- camera_override.fov = p_fovy_degrees;
- camera_override.z_near = p_z_near;
- camera_override.z_far = p_z_far;
- camera_override.projection = CameraOverrideData::PROJECTION_PERSPECTIVE;
-
- RenderingServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far);
- }
-}
-
-void Viewport::set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far) {
- if (camera_override) {
- if (camera_override.size == p_size && camera_override.z_near == p_z_near &&
- camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_ORTHOGONAL)
- return;
-
- camera_override.size = p_size;
- camera_override.z_near = p_z_near;
- camera_override.z_far = p_z_far;
- camera_override.projection = CameraOverrideData::PROJECTION_ORTHOGONAL;
-
- RenderingServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far);
- }
+Camera2D *Viewport::get_camera_2d() const {
+ return camera_2d;
}
Transform2D Viewport::get_final_transform() const {
-
return stretch_transform * global_canvas_transform;
}
void Viewport::_update_canvas_items(Node *p_node) {
if (p_node != this) {
-
Viewport *vp = Object::cast_to<Viewport>(p_node);
- if (vp)
+ if (vp) {
return;
+ }
CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
if (ci) {
@@ -1452,49 +1024,53 @@ void Viewport::_update_canvas_items(Node *p_node) {
}
Ref<ViewportTexture> Viewport::get_texture() const {
-
return default_texture;
}
void Viewport::set_shadow_atlas_size(int p_size) {
-
- if (shadow_atlas_size == p_size)
- return;
-
shadow_atlas_size = p_size;
- RS::get_singleton()->viewport_set_shadow_atlas_size(viewport, p_size);
+ RS::get_singleton()->viewport_set_shadow_atlas_size(viewport, p_size, shadow_atlas_16_bits);
}
int Viewport::get_shadow_atlas_size() const {
-
return shadow_atlas_size;
}
-void Viewport::set_shadow_atlas_quadrant_subdiv(int p_quadrant, ShadowAtlasQuadrantSubdiv p_subdiv) {
+void Viewport::set_shadow_atlas_16_bits(bool p_16_bits) {
+ if (shadow_atlas_16_bits == p_16_bits) {
+ return;
+ }
+
+ shadow_atlas_16_bits = p_16_bits;
+ RS::get_singleton()->viewport_set_shadow_atlas_size(viewport, shadow_atlas_size, shadow_atlas_16_bits);
+}
+bool Viewport::get_shadow_atlas_16_bits() const {
+ return shadow_atlas_16_bits;
+}
+void Viewport::set_shadow_atlas_quadrant_subdiv(int p_quadrant, ShadowAtlasQuadrantSubdiv p_subdiv) {
ERR_FAIL_INDEX(p_quadrant, 4);
ERR_FAIL_INDEX(p_subdiv, SHADOW_ATLAS_QUADRANT_SUBDIV_MAX);
- if (shadow_atlas_quadrant_subdiv[p_quadrant] == p_subdiv)
+ if (shadow_atlas_quadrant_subdiv[p_quadrant] == p_subdiv) {
return;
+ }
shadow_atlas_quadrant_subdiv[p_quadrant] = p_subdiv;
static const int subdiv[SHADOW_ATLAS_QUADRANT_SUBDIV_MAX] = { 0, 1, 4, 16, 64, 256, 1024 };
RS::get_singleton()->viewport_set_shadow_atlas_quadrant_subdivision(viewport, p_quadrant, subdiv[p_subdiv]);
}
-Viewport::ShadowAtlasQuadrantSubdiv Viewport::get_shadow_atlas_quadrant_subdiv(int p_quadrant) const {
+Viewport::ShadowAtlasQuadrantSubdiv Viewport::get_shadow_atlas_quadrant_subdiv(int p_quadrant) const {
ERR_FAIL_INDEX_V(p_quadrant, 4, SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
return shadow_atlas_quadrant_subdiv[p_quadrant];
}
Transform2D Viewport::_get_input_pre_xform() const {
-
Transform2D pre_xf;
if (to_screen_rect.size.x != 0 && to_screen_rect.size.y != 0) {
-
pre_xf.elements[2] = -to_screen_rect.position;
pre_xf.scale(size / to_screen_rect.size);
}
@@ -1503,27 +1079,24 @@ Transform2D Viewport::_get_input_pre_xform() const {
}
Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
-
Transform2D ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
return ev->xformed_by(ai);
}
Vector2 Viewport::get_mouse_position() const {
-
return gui.last_mouse_pos;
}
void Viewport::warp_mouse(const Vector2 &p_pos) {
-
Vector2 gpos = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse().xform(p_pos);
- InputFilter::get_singleton()->warp_mouse_position(gpos);
+ Input::get_singleton()->warp_mouse_position(gpos);
}
void Viewport::_gui_sort_roots() {
-
- if (!gui.roots_order_dirty)
+ if (!gui.roots_order_dirty) {
return;
+ }
gui.roots.sort_custom<Control::CComparator>();
@@ -1531,9 +1104,11 @@ void Viewport::_gui_sort_roots() {
}
void Viewport::_gui_cancel_tooltip() {
-
- gui.tooltip = nullptr;
- gui.tooltip_timer = -1;
+ gui.tooltip_control = nullptr;
+ if (gui.tooltip_timer.is_valid()) {
+ gui.tooltip_timer->release_connections();
+ gui.tooltip_timer = Ref<SceneTreeTimer>();
+ }
if (gui.tooltip_popup) {
gui.tooltip_popup->queue_delete();
gui.tooltip_popup = nullptr;
@@ -1541,27 +1116,39 @@ void Viewport::_gui_cancel_tooltip() {
}
}
-String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which) {
-
+String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_tooltip_owner) {
Vector2 pos = p_pos;
String tooltip;
while (p_control) {
-
tooltip = p_control->get_tooltip(pos);
- if (r_which) {
- *r_which = p_control;
+ // Temporary solution for PopupMenus.
+ PopupMenu *menu = Object::cast_to<PopupMenu>(this);
+ if (menu) {
+ tooltip = menu->get_tooltip(pos);
+ }
+
+ if (r_tooltip_owner) {
+ *r_tooltip_owner = p_control;
}
- if (tooltip != String())
+ // If we found a tooltip, we stop here.
+ if (!tooltip.is_empty()) {
break;
- pos = p_control->get_transform().xform(pos);
+ }
+
+ // Otherwise, we check parent controls unless some conditions prevent it.
- if (p_control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
+ if (p_control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
break;
- if (p_control->is_set_as_toplevel())
+ }
+ if (p_control->is_set_as_top_level()) {
break;
+ }
+
+ // Transform cursor pos for parent control.
+ pos = p_control->get_transform().xform(pos);
p_control = p_control->get_parent_control();
}
@@ -1570,40 +1157,50 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont
}
void Viewport::_gui_show_tooltip() {
-
- if (!gui.tooltip) {
+ if (!gui.tooltip_control) {
return;
}
- Control *which = nullptr;
- String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which);
- tooltip = tooltip.strip_edges();
- if (tooltip.length() == 0)
- return; // bye
+ // Get the Control under cursor and the relevant tooltip text, if any.
+ Control *tooltip_owner = nullptr;
+ String tooltip_text = _gui_get_tooltip(
+ gui.tooltip_control,
+ gui.tooltip_control->get_global_transform().xform_inv(gui.last_mouse_pos),
+ &tooltip_owner);
+ tooltip_text = tooltip_text.strip_edges();
+ if (tooltip_text.is_empty()) {
+ return; // Nothing to show.
+ }
+ // Remove previous popup if we change something.
if (gui.tooltip_popup) {
memdelete(gui.tooltip_popup);
gui.tooltip_popup = nullptr;
gui.tooltip_label = nullptr;
}
- if (!which) {
+ if (!tooltip_owner) {
return;
}
- Control *rp = which;
+ // Popup window which houses the tooltip content.
+ TooltipPanel *panel = memnew(TooltipPanel);
- Control *base_tooltip = which->make_custom_tooltip(tooltip);
+ // 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);
+ // If no custom tooltip is given, use a default implementation.
if (!base_tooltip) {
gui.tooltip_label = memnew(TooltipLabel);
- gui.tooltip_label->set_text(tooltip);
+ gui.tooltip_label->set_auto_translate(gui.tooltip_control->is_auto_translating());
+ gui.tooltip_label->set_text(tooltip_text);
base_tooltip = gui.tooltip_label;
+ panel->connect("mouse_entered", callable_mp(this, &Viewport::_gui_cancel_tooltip));
}
- base_tooltip->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ 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);
@@ -1611,26 +1208,27 @@ void Viewport::_gui_show_tooltip() {
gui.tooltip_popup = panel;
- rp->add_child(gui.tooltip_popup);
-
- //if (gui.tooltip) // Avoids crash when rapidly switching controls.
- // gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
+ tooltip_owner->add_child(gui.tooltip_popup);
Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size());
- Rect2i vr = gui.tooltip_popup->get_parent_visible_window()->get_usable_parent_rect();
+ Window *window = gui.tooltip_popup->get_parent_visible_window();
+ Rect2i vr = window->get_usable_parent_rect();
- if (r.size.x + r.position.x > vr.size.x + vr.position.x)
+ if (r.size.x + r.position.x > vr.size.x + vr.position.x) {
r.position.x = vr.position.x + vr.size.x - r.size.x;
- else if (r.position.x < vr.position.x)
+ } else if (r.position.x < vr.position.x) {
r.position.x = vr.position.x;
+ }
- if (r.size.y + r.position.y > vr.size.y + vr.position.y)
+ if (r.size.y + r.position.y > vr.size.y + vr.position.y) {
r.position.y = vr.position.y + vr.size.y - r.size.y;
- else if (r.position.y < vr.position.y)
+ } else if (r.position.y < vr.position.y) {
r.position.y = vr.position.y;
+ }
+ gui.tooltip_popup->set_current_screen(window->get_current_screen());
gui.tooltip_popup->set_position(r.position);
gui.tooltip_popup->set_size(r.size);
@@ -1639,19 +1237,16 @@ void Viewport::_gui_show_tooltip() {
}
void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_input) {
-
- //_block();
-
Ref<InputEvent> ev = p_input;
- //mouse wheel events can't be stopped
+ // Mouse wheel events can't be stopped.
Ref<InputEventMouseButton> mb = p_input;
bool cant_stop_me_now = (mb.is_valid() &&
- (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;
@@ -1659,214 +1254,186 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
CanvasItem *ci = p_control;
while (ci) {
-
Control *control = Object::cast_to<Control>(ci);
if (control) {
-
if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
- control->emit_signal(SceneStringNames::get_singleton()->gui_input, ev); //signal should be first, so it's possible to override an event (and then accept it)
- }
- if (gui.key_event_accepted)
- break;
- if (!control->is_inside_tree())
- break;
-
- if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
- control->call_multilevel(SceneStringNames::get_singleton()->_gui_input, ev);
+ control->_call_gui_input(ev);
}
- if (!control->is_inside_tree() || control->is_set_as_toplevel())
+ if (!control->is_inside_tree() || control->is_set_as_top_level()) {
break;
- if (gui.key_event_accepted)
+ }
+ if (gui.key_event_accepted) {
break;
- if (!cant_stop_me_now && control->data.mouse_filter == Control::MOUSE_FILTER_STOP && ismouse)
+ }
+ if (!cant_stop_me_now && control->data.mouse_filter == Control::MOUSE_FILTER_STOP && ismouse) {
break;
+ }
}
- if (ci->is_set_as_toplevel())
+ if (ci->is_set_as_top_level()) {
break;
+ }
- ev = ev->xformed_by(ci->get_transform()); //transform event upwards
+ ev = ev->xformed_by(ci->get_transform()); // Transform event upwards.
ci = ci->get_parent_item();
}
-
- //_unblock();
}
void Viewport::_gui_call_notification(Control *p_control, int p_what) {
-
CanvasItem *ci = p_control;
while (ci) {
-
Control *control = Object::cast_to<Control>(ci);
if (control) {
-
if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
control->notification(p_what);
}
- if (!control->is_inside_tree())
+ if (!control->is_inside_tree()) {
break;
+ }
- if (!control->is_inside_tree() || control->is_set_as_toplevel())
+ if (!control->is_inside_tree() || control->is_set_as_top_level()) {
break;
- if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
+ }
+ if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
break;
+ }
}
- if (ci->is_set_as_toplevel())
+ if (ci->is_set_as_top_level()) {
break;
+ }
ci = ci->get_parent_item();
}
-
- //_unblock();
}
-Control *Viewport::_gui_find_control(const Point2 &p_global) {
- //aca va subwindows
+Control *Viewport::gui_find_control(const Point2 &p_global) {
+ // Handle subwindows.
_gui_sort_roots();
for (List<Control *>::Element *E = gui.roots.back(); E; E = E->prev()) {
-
Control *sw = E->get();
- if (!sw->is_visible_in_tree())
+ if (!sw->is_visible_in_tree()) {
continue;
+ }
Transform2D xform;
CanvasItem *pci = sw->get_parent_item();
- if (pci)
+ if (pci) {
xform = pci->get_global_transform_with_canvas();
- else
+ } else {
xform = sw->get_canvas_transform();
+ }
Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform);
- if (ret)
+ if (ret) {
return ret;
+ }
}
return nullptr;
}
Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) {
-
- if (Object::cast_to<Viewport>(p_node))
+ if (Object::cast_to<Viewport>(p_node)) {
return nullptr;
+ }
if (!p_node->is_visible()) {
- //return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform);
- return nullptr; //canvas item hidden, discard
+ return nullptr; // Canvas item hidden, discard.
}
Transform2D matrix = p_xform * p_node->get_transform();
// matrix.basis_determinant() == 0.0f implies that node does not exist on scene
- if (matrix.basis_determinant() == 0.0f)
+ if (matrix.basis_determinant() == 0.0f) {
return nullptr;
+ }
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_toplevel())
+ if (!ci || ci->is_set_as_top_level()) {
continue;
+ }
Control *ret = _gui_find_control_at_pos(ci, p_global, matrix, r_inv_xform);
- if (ret)
+ if (ret) {
return ret;
+ }
}
}
- 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) {
-
- { //attempt grab, try parent controls too
- CanvasItem *ci = p_at_control;
- while (ci) {
-
- Control *control = Object::cast_to<Control>(ci);
- if (control) {
-
- if (control->can_drop_data(p_at_pos, gui.drag_data)) {
- if (!p_just_check) {
- control->drop_data(p_at_pos, gui.drag_data);
- }
-
- return true;
+ // Attempt grab, try parent controls too.
+ CanvasItem *ci = p_at_control;
+ while (ci) {
+ Control *control = Object::cast_to<Control>(ci);
+ if (control) {
+ if (control->can_drop_data(p_at_pos, gui.drag_data)) {
+ if (!p_just_check) {
+ control->drop_data(p_at_pos, gui.drag_data);
}
- if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
- break;
+ return true;
}
- p_at_pos = ci->get_transform().xform(p_at_pos);
-
- if (ci->is_set_as_toplevel())
+ if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
break;
+ }
+ }
- ci = ci->get_parent_item();
+ p_at_pos = ci->get_transform().xform(p_at_pos);
+
+ if (ci->is_set_as_top_level()) {
+ break;
}
+
+ ci = ci->get_parent_item();
}
return false;
}
void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
-
ERR_FAIL_COND(p_event.is_null());
- //?
- /*
- if (!is_visible()) {
- return; //simple and plain
- }
- */
-
Ref<InputEventMouseButton> mb = p_event;
-
if (mb.is_valid()) {
-
gui.key_event_accepted = false;
+ 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) {
-
- //do not steal mouse focus and stuff while a focus mask exists
- gui.mouse_focus_mask |= 1 << (mb->get_button_index() - 1); //add the button to the mask
+ // Do not steal mouse focus and stuff while a focus mask exists.
+ gui.mouse_focus_mask |= 1 << (mb->get_button_index() - 1); // Add the button to the mask.
} else {
-
- bool is_handled = false;
-
- if (is_handled) {
- set_input_as_handled();
- return;
- }
-
- //Matrix32 parent_xform;
-
- /*
- if (data.parent_canvas_item)
- parent_xform=data.parent_canvas_item->get_global_transform();
- */
-
- gui.mouse_focus = _gui_find_control(pos);
+ gui.mouse_focus = gui_find_control(pos);
gui.last_mouse_focus = gui.mouse_focus;
if (!gui.mouse_focus) {
@@ -1876,13 +1443,13 @@ 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;
}
}
- mb = mb->xformed_by(Transform2D()); // make a copy of the event
+ mb = mb->xformed_by(Transform2D()); // Make a copy of the event.
mb->set_global_position(pos);
@@ -1892,7 +1459,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
#ifdef DEBUG_ENABLED
if (EngineDebugger::get_singleton() && gui.mouse_focus) {
-
Array arr;
arr.push_back(gui.mouse_focus->get_path());
arr.push_back(gui.mouse_focus->get_class());
@@ -1900,10 +1466,9 @@ 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);
if (control) {
if (control->get_focus_mode() != Control::FOCUS_NONE) {
@@ -1913,12 +1478,14 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
break;
}
- if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
+ if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
break;
+ }
}
- if (ci->is_set_as_toplevel())
+ if (ci->is_set_as_top_level()) {
break;
+ }
ci = ci->get_parent_item();
}
@@ -1930,9 +1497,8 @@ 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) {
-
- //alternate drop use (when using force_drag(), as proposed by #5342
+ 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);
}
@@ -1940,54 +1506,54 @@ 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
+ // Change mouse accordingly.
}
_gui_cancel_tooltip();
- //gui.tooltip_popup->hide();
-
} 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();
gui.dragging = false;
gui.drag_mouse_over = nullptr;
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
- //change mouse accordingly
+ // Change mouse accordingly.
}
- gui.mouse_focus_mask &= ~(1 << (mb->get_button_index() - 1)); //remove from mask
+ gui.mouse_focus_mask &= ~(1 << (mb->get_button_index() - 1)); // Remove from mask.
if (!gui.mouse_focus) {
- //release event is only sent if a mouse focus (previously pressed button) exists
+ // Release event is only sent if a mouse focus (previously pressed button) exists.
return;
}
Size2 pos = mpos;
- mb = mb->xformed_by(Transform2D()); //make a copy
+ mb = mb->xformed_by(Transform2D()); // Make a copy.
mb->set_global_position(pos);
pos = gui.focus_inv_xform.xform(pos);
mb->set_position(pos);
Control *mouse_focus = gui.mouse_focus;
- //disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise
+ // Disable mouse focus if needed before calling input,
+ // this makes popups on mouse press event work better,
+ // as the release will never be received otherwise.
if (gui.mouse_focus_mask == 0) {
gui.mouse_focus = nullptr;
gui.forced_mouse_focus = false;
@@ -1997,19 +1563,37 @@ 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) {
- _propagate_viewport_notification(this,NOTIFICATION_DRAG_END);
- gui.drag_data=Variant(); //always clear
- }*/
+ // In case the mouse was released after for example dragging a scrollbar,
+ // check whether the current control is different from the stored one. If
+ // it is different, rather than wait for it to be updated the next time the
+ // mouse is moved, notify the control so that it can e.g. drop the highlight.
+ // This code is duplicated from the mm.is_valid()-case further below.
+ if (gui.mouse_focus) {
+ over = gui.mouse_focus;
+ } else {
+ over = gui_find_control(mpos);
+ }
+
+ if (gui.mouse_focus_mask == 0 && over != gui.mouse_over) {
+ if (gui.mouse_over) {
+ _gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT);
+ }
+
+ _gui_cancel_tooltip();
+
+ if (over) {
+ _gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER);
+ }
+ }
+
+ gui.mouse_over = over;
set_input_as_handled();
}
}
Ref<InputEventMouseMotion> mm = p_event;
-
if (mm.is_valid()) {
-
gui.key_event_accepted = false;
Point2 mpos = mm->get_position();
@@ -2017,43 +1601,41 @@ 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) {
-
+ // Drag & drop.
+ if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
gui.drag_accum += mm->get_relative();
float len = gui.drag_accum.length();
if (len > 10) {
-
- { //attempt grab, try parent controls too
+ { // Attempt grab, try parent controls too.
CanvasItem *ci = gui.mouse_focus;
while (ci) {
-
Control *control = Object::cast_to<Control>(ci);
if (control) {
-
gui.dragging = true;
gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos) - gui.drag_accum);
if (gui.drag_data.get_type() != Variant::NIL) {
-
gui.mouse_focus = nullptr;
gui.forced_mouse_focus = false;
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;
}
- if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
+ if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
break;
+ }
}
- if (ci->is_set_as_toplevel())
+ if (ci->is_set_as_top_level()) {
break;
+ }
ci = ci->get_parent_item();
}
@@ -2061,23 +1643,21 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_attempted = true;
if (gui.drag_data.get_type() != Variant::NIL) {
-
_propagate_viewport_notification(this, NOTIFICATION_DRAG_BEGIN);
}
}
}
+ // These sections of code are reused in the mb.is_valid() case further up
+ // for the purpose of notifying controls about potential changes in focus
+ // when the mousebutton is released.
if (gui.mouse_focus) {
over = gui.mouse_focus;
- //recompute focus_inv_xform again here
-
} else {
-
- over = _gui_find_control(mpos);
+ over = gui_find_control(mpos);
}
if (over != gui.mouse_over) {
-
if (gui.mouse_over) {
_gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT);
}
@@ -2091,40 +1671,38 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.mouse_over = over;
- DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)InputFilter::get_singleton()->get_default_cursor_shape();
+ DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)Input::get_singleton()->get_default_cursor_shape();
if (over) {
-
Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
Size2 pos = localizer.xform(mpos);
Vector2 speed = localizer.basis_xform(mm->get_speed());
Vector2 rel = localizer.basis_xform(mm->get_relative());
- mm = mm->xformed_by(Transform2D()); //make a copy
+ mm = mm->xformed_by(Transform2D()); // Make a copy.
mm->set_global_position(mpos);
mm->set_speed(speed);
mm->set_relative(rel);
if (mm->get_button_mask() == 0) {
- //nothing pressed
+ // Nothing pressed.
bool can_tooltip = true;
bool is_tooltip_shown = false;
if (gui.tooltip_popup) {
- if (can_tooltip && gui.tooltip) {
- String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos));
+ if (can_tooltip && gui.tooltip_control) {
+ String tooltip = _gui_get_tooltip(over, gui.tooltip_control->get_global_transform().xform_inv(mpos));
- if (tooltip.length() == 0)
+ if (tooltip.length() == 0) {
_gui_cancel_tooltip();
- else if (gui.tooltip_label) {
+ } else if (gui.tooltip_label) {
if (tooltip == gui.tooltip_label->get_text()) {
is_tooltip_shown = true;
}
} else {
-
Variant t = gui.tooltip_popup->call("get_tooltip_text");
if (t.get_type() == Variant::STRING) {
@@ -2132,23 +1710,27 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
is_tooltip_shown = true;
}
} else {
- is_tooltip_shown = true; //well, nothing to compare against, likely using custom control, so if it changes there is nothing we can do
+ is_tooltip_shown = true; // Nothing to compare against, likely using custom control, so if it changes there is nothing we can do.
}
}
- } else
+ } else {
_gui_cancel_tooltip();
+ }
}
if (can_tooltip && !is_tooltip_shown) {
-
- gui.tooltip = over;
- gui.tooltip_pos = over->get_screen_transform().xform(pos); //(parent_xform * get_transform()).affine_inverse().xform(pos);
- gui.tooltip_timer = gui.tooltip_delay;
+ if (gui.tooltip_timer.is_valid()) {
+ gui.tooltip_timer->release_connections();
+ gui.tooltip_timer = Ref<SceneTreeTimer>();
+ }
+ gui.tooltip_control = over;
+ gui.tooltip_pos = over->get_screen_transform().xform(pos);
+ gui.tooltip_timer = get_tree()->create_timer(gui.tooltip_delay);
+ gui.tooltip_timer->set_ignore_time_scale(true);
+ gui.tooltip_timer->connect("timeout", callable_mp(this, &Viewport::_gui_show_tooltip));
}
}
- //pos = gui.focus_inv_xform.xform(pos);
-
mm->set_position(pos);
Control::CursorShape cursor_shape = Control::CURSOR_ARROW;
@@ -2156,14 +1738,21 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *c = over;
Vector2 cpos = pos;
while (c) {
- cursor_shape = c->get_cursor_shape(cpos);
+ if (gui.mouse_focus_mask != 0 || c->has_point(cpos)) {
+ cursor_shape = c->get_cursor_shape(cpos);
+ } else {
+ cursor_shape = Control::CURSOR_ARROW;
+ }
cpos = c->get_transform().xform(cpos);
- if (cursor_shape != Control::CURSOR_ARROW)
+ if (cursor_shape != Control::CURSOR_ARROW) {
break;
- if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP)
+ }
+ if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
break;
- if (c->is_set_as_toplevel())
+ }
+ if (c->is_set_as_top_level()) {
break;
+ }
c = c->get_parent_control();
}
}
@@ -2178,18 +1767,18 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (gui.drag_data.get_type() != Variant::NIL) {
- //handle dragandrop
+ // Handle drag & drop.
- 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;
gui.drag_mouse_over_pos = Vector2();
- //find the window this is above of
-
- //see if there is an embedder
+ // Find the window this is above of.
+ // See if there is an embedder.
Viewport *embedder = nullptr;
Vector2 viewport_pos;
@@ -2197,7 +1786,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()) {
@@ -2205,7 +1794,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Transform2D ai = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse();
- viewport_pos = ai.xform(mpos) + w->get_position(); //to parent coords
+ viewport_pos = ai.xform(mpos) + w->get_position(); // To parent coords.
}
}
}
@@ -2213,13 +1802,13 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Viewport *viewport_under = nullptr;
if (embedder) {
- //use embedder logic
+ // Use embedder logic.
for (int i = embedder->gui.sub_windows.size() - 1; i >= 0; i--) {
Window *sw = embedder->gui.sub_windows[i].window;
Rect2 swrect = Rect2i(sw->get_position(), sw->get_size());
if (!sw->get_flag(Window::FLAG_BORDERLESS)) {
- int title_height = sw->get_theme_constant("title_height");
+ int title_height = sw->get_theme_constant(SNAME("title_height"));
swrect.position.y -= title_height;
swrect.size.y += title_height;
}
@@ -2231,11 +1820,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (!viewport_under) {
- //not in a subwindow, likely in embedder
+ // Not in a subwindow, likely in embedder.
viewport_under = embedder;
}
} else {
- //use displayserver logic
+ // Use DisplayServer logic.
Vector2i screen_mouse_pos = DisplayServer::get_singleton()->mouse_get_position();
DisplayServer::WindowID window_id = DisplayServer::get_singleton()->get_window_at_screen_position(screen_mouse_pos);
@@ -2243,7 +1832,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
ObjectID object_under = DisplayServer::get_singleton()->window_get_attached_instance_id(window_id);
- if (object_under != ObjectID()) { //fetch window
+ if (object_under != ObjectID()) { // Fetch window.
Window *w = Object::cast_to<Window>(ObjectDB::get_instance(object_under));
if (w) {
viewport_under = w;
@@ -2256,14 +1845,13 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (viewport_under) {
Transform2D ai = (viewport_under->get_final_transform().affine_inverse() * viewport_under->_get_input_pre_xform());
viewport_pos = ai.xform(viewport_pos);
- //find control under at pos
- gui.drag_mouse_over = viewport_under->_gui_find_control(viewport_pos);
+ // Find control under at position.
+ gui.drag_mouse_over = viewport_under->gui_find_control(viewport_pos);
if (gui.drag_mouse_over) {
Transform2D localizer = gui.drag_mouse_over->get_global_transform_with_canvas().affine_inverse();
gui.drag_mouse_over_pos = localizer.xform(viewport_pos);
- 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) {
@@ -2284,16 +1872,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Ref<InputEventScreenTouch> touch_event = p_event;
if (touch_event.is_valid()) {
-
Size2 pos = touch_event->get_position();
if (touch_event->is_pressed()) {
-
- Control *over = _gui_find_control(pos);
+ Control *over = gui_find_control(pos);
if (over) {
-
if (over->can_process()) {
-
- touch_event = touch_event->xformed_by(Transform2D()); //make a copy
+ touch_event = touch_event->xformed_by(Transform2D()); // Make a copy.
if (over == gui.mouse_focus) {
pos = gui.focus_inv_xform.xform(pos);
} else {
@@ -2306,10 +1890,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
return;
}
} else if (touch_event->get_index() == 0 && gui.last_mouse_focus) {
-
if (gui.last_mouse_focus->can_process()) {
-
- touch_event = touch_event->xformed_by(Transform2D()); //make a copy
+ touch_event = touch_event->xformed_by(Transform2D()); // Make a copy.
touch_event->set_position(gui.focus_inv_xform.xform(pos));
_gui_call_input(gui.last_mouse_focus, touch_event);
@@ -2321,19 +1903,16 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Ref<InputEventGesture> gesture_event = p_event;
if (gesture_event.is_valid()) {
-
gui.key_event_accepted = false;
_gui_cancel_tooltip();
Size2 pos = gesture_event->get_position();
- Control *over = _gui_find_control(pos);
+ Control *over = gui_find_control(pos);
if (over) {
-
if (over->can_process()) {
-
- gesture_event = gesture_event->xformed_by(Transform2D()); //make a copy
+ gesture_event = gesture_event->xformed_by(Transform2D()); // Make a copy.
if (over == gui.mouse_focus) {
pos = gui.focus_inv_xform.xform(pos);
} else {
@@ -2349,21 +1928,18 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Ref<InputEventScreenDrag> drag_event = 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()) {
-
Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
Size2 pos = localizer.xform(drag_event->get_position());
Vector2 speed = localizer.basis_xform(drag_event->get_speed());
Vector2 rel = localizer.basis_xform(drag_event->get_relative());
- drag_event = drag_event->xformed_by(Transform2D()); //make a copy
+ drag_event = drag_event->xformed_by(Transform2D()); // Make a copy.
drag_event->set_speed(speed);
drag_event->set_relative(rel);
@@ -2378,69 +1954,54 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (mm.is_null() && mb.is_null() && p_event->is_action_type()) {
-
if (gui.key_focus && !gui.key_focus->is_visible_in_tree()) {
gui.key_focus->release_focus();
}
if (gui.key_focus) {
-
gui.key_event_accepted = false;
if (gui.key_focus->can_process()) {
- gui.key_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, p_event);
- if (gui.key_focus) //maybe lost it
- gui.key_focus->emit_signal(SceneStringNames::get_singleton()->gui_input, p_event);
+ gui.key_focus->_call_gui_input(p_event);
}
if (gui.key_event_accepted) {
-
set_input_as_handled();
return;
}
}
- 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()) {
+ Control *from = gui.key_focus ? gui.key_focus : nullptr;
+ // Keyboard focus.
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;
- InputFilter *input = InputFilter::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")) {
-
- next = from->_get_focus_neighbour(MARGIN_TOP);
+ 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")) {
-
- next = from->_get_focus_neighbour(MARGIN_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")) {
-
- next = from->_get_focus_neighbour(MARGIN_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")) {
-
- next = from->_get_focus_neighbour(MARGIN_BOTTOM);
+ if (!mods && p_event->is_action_pressed("ui_down", true)) {
+ next = from->_get_focus_neighbor(SIDE_BOTTOM);
}
if (next) {
@@ -2452,7 +2013,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
-
gui.roots_order_dirty = true;
return gui.roots.push_back(p_control);
}
@@ -2462,7 +2022,6 @@ void Viewport::_gui_set_root_order_dirty() {
}
void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control) {
-
ERR_FAIL_COND_MSG(p_data.get_type() == Variant::NIL, "Drag data must be a value.");
gui.dragging = true;
@@ -2475,53 +2034,66 @@ void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *
}
void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
-
ERR_FAIL_NULL(p_control);
ERR_FAIL_COND(!Object::cast_to<Control>((Object *)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_toplevel(true);
+ p_control->set_as_top_level(true);
p_control->set_position(gui.last_mouse_pos);
- p_base->get_root_parent_control()->add_child(p_control); //add as child of viewport
+ p_base->get_root_parent_control()->add_child(p_control); // Add as child of viewport.
p_control->raise();
- gui.drag_preview = p_control;
+ gui.drag_preview_id = p_control->get_instance_id();
}
-void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) {
+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) {
gui.roots.erase(RI);
}
void Viewport::_gui_unfocus_control(Control *p_control) {
-
if (gui.key_focus == p_control) {
gui.key_focus->release_focus();
}
}
-void Viewport::_gui_hid_control(Control *p_control) {
-
+void Viewport::_gui_hide_control(Control *p_control) {
if (gui.mouse_focus == p_control) {
_drop_mouse_focus();
}
- if (gui.key_focus == p_control)
+ if (gui.key_focus == p_control) {
_gui_remove_focus();
- if (gui.mouse_over == p_control)
+ }
+ if (gui.mouse_over == p_control) {
gui.mouse_over = nullptr;
- if (gui.drag_mouse_over == p_control)
+ }
+ if (gui.drag_mouse_over == p_control) {
gui.drag_mouse_over = nullptr;
- if (gui.tooltip == p_control)
+ }
+ if (gui.tooltip_control == p_control) {
_gui_cancel_tooltip();
+ }
}
void Viewport::_gui_remove_control(Control *p_control) {
-
if (gui.mouse_focus == p_control) {
gui.mouse_focus = nullptr;
gui.forced_mouse_focus = false;
@@ -2530,18 +2102,39 @@ void Viewport::_gui_remove_control(Control *p_control) {
if (gui.last_mouse_focus == p_control) {
gui.last_mouse_focus = nullptr;
}
- if (gui.key_focus == p_control)
+ if (gui.key_focus == p_control) {
gui.key_focus = nullptr;
- if (gui.mouse_over == p_control)
+ }
+ if (gui.mouse_over == p_control) {
gui.mouse_over = nullptr;
- if (gui.drag_mouse_over == p_control)
+ }
+ if (gui.drag_mouse_over == p_control) {
gui.drag_mouse_over = nullptr;
- if (gui.tooltip == p_control)
- gui.tooltip = nullptr;
+ }
+ if (gui.tooltip_control == p_control) {
+ gui.tooltip_control = nullptr;
+ }
}
-void Viewport::_gui_remove_focus() {
+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) {
+ v = v->get_parent_viewport();
+ w = Object::cast_to<Window>(v);
+ }
+ return w;
+}
+void Viewport::_gui_remove_focus_for_window(Node *p_window) {
+ if (get_base_window() == p_window) {
+ _gui_remove_focus();
+ }
+}
+
+void Viewport::_gui_remove_focus() {
if (gui.key_focus) {
Node *f = gui.key_focus;
gui.key_focus = nullptr;
@@ -2550,31 +2143,29 @@ void Viewport::_gui_remove_focus() {
}
bool Viewport::_gui_control_has_focus(const Control *p_control) {
-
return gui.key_focus == p_control;
}
void Viewport::_gui_control_grab_focus(Control *p_control) {
-
- //no need for change
- if (gui.key_focus && gui.key_focus == p_control)
+ if (gui.key_focus && gui.key_focus == p_control) {
+ // No need for change.
return;
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "_viewports", "_gui_remove_focus");
+ }
+ 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();
}
void Viewport::_gui_accept_event() {
-
gui.key_event_accepted = true;
- if (is_inside_tree())
+ if (is_inside_tree()) {
set_input_as_handled();
+ }
}
void Viewport::_drop_mouse_focus() {
-
Control *c = gui.mouse_focus;
int mask = gui.mouse_focus_mask;
gui.mouse_focus = nullptr;
@@ -2582,86 +2173,126 @@ void Viewport::_drop_mouse_focus() {
gui.mouse_focus_mask = 0;
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_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+ c->_call_gui_input(mb);
}
}
}
-void Viewport::_drop_physics_mouseover() {
-
+void Viewport::_drop_physics_mouseover(bool p_paused_only) {
physics_has_last_mousepos = false;
- while (physics_2d_mouseover.size()) {
- Object *o = ObjectDB::get_instance(physics_2d_mouseover.front()->key());
- if (o) {
- CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
- co->_mouse_exit();
- }
- physics_2d_mouseover.erase(physics_2d_mouseover.front());
- }
+ _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) {
- co->_mouse_exit();
+ if (!(p_paused_only && co->can_process())) {
+ co->_mouse_exit();
+ physics_object_over = ObjectID();
+ physics_object_capture = ObjectID();
+ }
}
}
+#endif // _3D_DISABLED
+}
- 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_clean_all_frames && p_paused_only && co->can_process()) {
+ continue;
+ }
+ co->_mouse_exit();
+ }
+ }
+ to_erase.push_back(E);
+ }
+
+ while (to_erase.size()) {
+ physics_2d_mouseover.erase(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+
+ // 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();
+ }
}
Control *Viewport::_gui_get_focus_owner() {
-
return gui.key_focus;
}
void Viewport::_gui_grab_click_focus(Control *p_control) {
-
gui.mouse_click_grabber = p_control;
- call_deferred("_post_gui_grab_click_focus");
+ call_deferred(SNAME("_post_gui_grab_click_focus"));
}
void Viewport::_post_gui_grab_click_focus() {
-
Control *focus_grabber = gui.mouse_click_grabber;
if (!focus_grabber) {
- // Redundant grab requests were made
+ // Redundant grab requests were made.
return;
}
gui.mouse_click_grabber = nullptr;
if (gui.mouse_focus) {
-
- if (gui.mouse_focus == focus_grabber)
+ if (gui.mouse_focus == focus_grabber) {
return;
+ }
int mask = gui.mouse_focus_mask;
Point2 click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
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_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+ gui.mouse_focus->_call_gui_input(mb);
}
}
@@ -2670,18 +2301,16 @@ void Viewport::_post_gui_grab_click_focus() {
click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
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);
+ MessageQueue::get_singleton()->push_callable(callable_mp(gui.mouse_focus, &Control::_call_gui_input), mb);
}
}
}
@@ -2689,10 +2318,9 @@ void Viewport::_post_gui_grab_click_focus() {
///////////////////////////////
-void Viewport::input_text(const String &p_text) {
-
+void Viewport::push_text_input(const String &p_text) {
if (gui.subwindow_focused) {
- gui.subwindow_focused->input_text(p_text);
+ gui.subwindow_focused->push_text_input(p_text);
return;
}
@@ -2700,27 +2328,27 @@ void Viewport::input_text(const String &p_text) {
gui.key_focus->call("set_text", p_text);
}
}
-Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point) {
+Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point) {
if (p_subwindow->get_flag(Window::FLAG_BORDERLESS)) {
return SUB_WINDOW_RESIZE_DISABLED;
}
Rect2i r = Rect2i(p_subwindow->get_position(), p_subwindow->get_size());
- int title_height = p_subwindow->get_theme_constant("title_height");
+ int title_height = p_subwindow->get_theme_constant(SNAME("title_height"));
r.position.y -= title_height;
r.size.y += title_height;
if (r.has_point(p_point)) {
- return SUB_WINDOW_RESIZE_DISABLED; //it's inside, so no resize
+ return SUB_WINDOW_RESIZE_DISABLED; // It's inside, so no resize.
}
int dist_x = p_point.x < r.position.x ? (p_point.x - r.position.x) : (p_point.x > (r.position.x + r.size.x) ? (p_point.x - (r.position.x + r.size.x)) : 0);
int dist_y = p_point.y < r.position.y ? (p_point.y - r.position.y) : (p_point.y > (r.position.y + r.size.y) ? (p_point.y - (r.position.y + r.size.y)) : 0);
- int limit = p_subwindow->get_theme_constant("resize_margin");
+ int limit = p_subwindow->get_theme_constant(SNAME("resize_margin"));
if (ABS(dist_x) > limit) {
return SUB_WINDOW_RESIZE_DISABLED;
@@ -2764,33 +2392,51 @@ Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subw
return SUB_WINDOW_RESIZE_DISABLED;
}
-bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
+bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) {
-
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
+ // Close window.
gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST);
}
}
gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
- if (gui.subwindow_focused != nullptr) { //may have been erased
+ if (gui.subwindow_focused != nullptr) { // May have been erased.
_sub_window_update(gui.subwindow_focused);
}
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
-
if (gui.subwindow_drag == SUB_WINDOW_DRAG_MOVE) {
Vector2 diff = mm->get_position() - gui.subwindow_drag_from;
Rect2i new_rect(gui.subwindow_drag_pos + diff, gui.subwindow_focused->get_size());
+
+ if (gui.subwindow_focused->is_clamped_to_embedder()) {
+ Size2i limit = get_visible_rect().size;
+ if (new_rect.position.x + new_rect.size.x > limit.x) {
+ new_rect.position.x = limit.x - new_rect.size.x;
+ }
+ if (new_rect.position.y + new_rect.size.y > limit.y) {
+ new_rect.position.y = limit.y - new_rect.size.y;
+ }
+
+ if (new_rect.position.x < 0) {
+ new_rect.position.x = 0;
+ }
+
+ 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;
+ }
+ }
+
gui.subwindow_focused->_rect_changed_callback(new_rect);
}
if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) {
@@ -2813,7 +2459,6 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
switch (gui.subwindow_resize_mode) {
case SUB_WINDOW_RESIZE_TOP_LEFT: {
-
diff.x = MIN(diff.x, limit.x);
diff.y = MIN(diff.y, limit.y);
r.position += diff;
@@ -2868,57 +2513,53 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
gui.subwindow_focused->_rect_changed_callback(r);
}
- if (gui.subwindow_focused) { //may have been erased
+ if (gui.subwindow_focused) { // May have been erased.
_sub_window_update(gui.subwindow_focused);
}
}
- return true; //handled
+ return true; // Handled.
}
Ref<InputEventMouseButton> mb = p_event;
- //if the event is a mouse button, we need to check whether another window was clicked
-
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ // If the event is a mouse button, we need to check whether another window was clicked.
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
bool click_on_window = false;
for (int i = gui.sub_windows.size() - 1; i >= 0; i--) {
SubWindow &sw = gui.sub_windows.write[i];
- //clicked inside window?
+ // Clicked inside window?
Rect2i r = Rect2i(sw.window->get_position(), sw.window->get_size());
if (!sw.window->get_flag(Window::FLAG_BORDERLESS)) {
- //check top bar
- int title_height = sw.window->get_theme_constant("title_height");
+ // Check top bar.
+ int title_height = sw.window->get_theme_constant(SNAME("title_height"));
Rect2i title_bar = r;
title_bar.position.y -= title_height;
title_bar.size.y = title_height;
if (title_bar.has_point(mb->get_position())) {
-
click_on_window = true;
- int close_h_ofs = sw.window->get_theme_constant("close_h_ofs");
- int close_v_ofs = sw.window->get_theme_constant("close_v_ofs");
- Ref<Texture2D> close_icon = sw.window->get_theme_icon("close");
+ int close_h_ofs = sw.window->get_theme_constant(SNAME("close_h_ofs"));
+ int close_v_ofs = sw.window->get_theme_constant(SNAME("close_v_ofs"));
+ Ref<Texture2D> close_icon = sw.window->get_theme_icon(SNAME("close"));
Rect2 close_rect;
close_rect.position = Vector2(r.position.x + r.size.x - close_v_ofs, r.position.y - close_h_ofs);
close_rect.size = close_icon->get_size();
if (gui.subwindow_focused != sw.window) {
- //refocus
+ // Refocus.
_sub_window_grab_focus(sw.window);
}
if (close_rect.has_point(mb->get_position())) {
-
gui.subwindow_drag = SUB_WINDOW_DRAG_CLOSE;
- gui.subwindow_drag_close_inside = true; //starts inside
+ gui.subwindow_drag_close_inside = true; // Starts inside.
gui.subwindow_drag_close_rect = close_rect;
} else {
-
gui.subwindow_drag = SUB_WINDOW_DRAG_MOVE;
}
@@ -2937,9 +2578,9 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
}
}
if (!click_on_window && r.has_point(mb->get_position())) {
- //clicked, see if it needs to fetch focus
+ // Clicked, see if it needs to fetch focus.
if (gui.subwindow_focused != sw.window) {
- //refocus
+ // Refocus.
_sub_window_grab_focus(sw.window);
}
@@ -2952,19 +2593,16 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
}
if (!click_on_window && gui.subwindow_focused) {
- //no window found and clicked, remove focus
+ // No window found and clicked, remove focus.
_sub_window_grab_focus(nullptr);
}
}
if (gui.subwindow_focused) {
-
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
-
SubWindowResize resize = _sub_window_get_resize_margin(gui.subwindow_focused, mm->get_position());
if (resize != SUB_WINDOW_RESIZE_DISABLED) {
-
DisplayServer::CursorShape shapes[SUB_WINDOW_RESIZE_MAX] = {
DisplayServer::CURSOR_ARROW,
DisplayServer::CURSOR_FDIAGSIZE,
@@ -2979,13 +2617,13 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]);
- return true; //reserved for showing the resize cursor
+ return true; // Reserved for showing the resize cursor.
}
}
}
if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) {
- return true; // dragging, don't pass the event
+ return true; // Dragging, don't pass the event.
}
if (!gui.subwindow_focused) {
@@ -3002,14 +2640,14 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
return true;
}
-void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
-
+void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(!is_inside_tree());
- if (disable_input)
+ if (disable_input) {
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;
}
@@ -3027,24 +2665,31 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
return;
}
+ if (!_can_consume_input_events()) {
+ return;
+ }
+
if (!is_input_handled()) {
- get_tree()->_call_input_pause(input_group, "_input", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
+ get_tree()->_call_input_pause(input_group, SceneTree::CALL_INPUT_TYPE_INPUT, ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
}
if (!is_input_handled()) {
_gui_input_event(ev);
}
- //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",ev); //special one for GUI, as controls use their own process check
-}
-void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
+ event_count++;
+}
+void Viewport::push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
+ ERR_FAIL_COND(p_event.is_null());
ERR_FAIL_COND(!is_inside_tree());
+ local_input_handled = false;
- if (disable_input)
+ 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;
}
@@ -3055,21 +2700,21 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor
ev = p_event;
}
- get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", ev, this);
- //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev);
- if (!is_input_handled() && Object::cast_to<InputEventKey>(*ev) != nullptr) {
- get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", ev, this);
- //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev);
+ // Unhandled Input.
+ get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, ev, this);
+
+ // Unhandled key Input - used for performance reasons - This is called a lot less than _unhandled_input since it ignores MouseMotion, etc.
+ if (!is_input_handled() && (Object::cast_to<InputEventKey>(*ev) != nullptr || Object::cast_to<InputEventShortcut>(*ev) != nullptr)) {
+ get_tree()->_call_input_pause(unhandled_key_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT, ev, this);
}
if (physics_object_picking && !is_input_handled()) {
-
- if (InputFilter::get_singleton()->get_mouse_mode() != InputFilter::MOUSE_MODE_CAPTURED &&
+ if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED &&
(Object::cast_to<InputEventMouseButton>(*ev) ||
Object::cast_to<InputEventMouseMotion>(*ev) ||
Object::cast_to<InputEventScreenDrag>(*ev) ||
Object::cast_to<InputEventScreenTouch>(*ev) ||
- Object::cast_to<InputEventKey>(*ev) //to remember state
+ Object::cast_to<InputEventKey>(*ev) // To remember state.
)) {
physics_picking_events.push_back(ev);
@@ -3077,64 +2722,28 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor
}
}
-void Viewport::set_use_own_world(bool p_world) {
-
- if (p_world == own_world.is_valid())
- return;
-
- if (is_inside_tree())
- _propagate_exit_world(this);
-
- if (!p_world) {
- own_world = Ref<World3D>();
- if (world.is_valid()) {
- world->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
- }
- } else {
- if (world.is_valid()) {
- own_world = world->duplicate();
- world->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
- } else {
- own_world = Ref<World3D>(memnew(World3D));
- }
- }
-
- if (is_inside_tree())
- _propagate_enter_world(this);
-
- if (is_inside_tree()) {
- RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
- }
-
- _update_listener();
-}
-
-bool Viewport::is_using_own_world() const {
-
- return own_world.is_valid();
-}
-
void Viewport::set_physics_object_picking(bool p_enable) {
-
physics_object_picking = p_enable;
- if (!physics_object_picking) {
+ if (physics_object_picking) {
+ add_to_group("_picking_viewports");
+ } else {
physics_picking_events.clear();
+ if (is_in_group("_picking_viewports")) {
+ remove_from_group("_picking_viewports");
+ }
}
}
bool Viewport::get_physics_object_picking() {
-
return physics_object_picking;
}
Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
-
Transform2D xf = get_final_transform();
return xf.xform(p_viewport_coords);
}
Vector2 Viewport::get_camera_rect_size() const {
-
return size;
}
@@ -3143,7 +2752,6 @@ void Viewport::set_disable_input(bool p_disable) {
}
bool Viewport::is_input_disabled() const {
-
return disable_input;
}
@@ -3151,79 +2759,124 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data;
}
-String Viewport::get_configuration_warning() const {
- /*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) {
-
- return TTR("This viewport is not set as render target. If you intend for it to display its contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign its internal texture to some node for display.");
- }*/
+TypedArray<String> Viewport::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (size.x == 0 || size.y == 0) {
- return 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 String();
+ return warnings;
}
void Viewport::gui_reset_canvas_sort_index() {
gui.canvas_sort_index = 0;
}
-int Viewport::gui_get_canvas_sort_index() {
+int Viewport::gui_get_canvas_sort_index() {
return gui.canvas_sort_index++;
}
void Viewport::set_msaa(MSAA p_msaa) {
-
ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
- if (msaa == p_msaa)
+ if (msaa == p_msaa) {
return;
+ }
msaa = p_msaa;
RS::get_singleton()->viewport_set_msaa(viewport, RS::ViewportMSAA(p_msaa));
}
Viewport::MSAA Viewport::get_msaa() const {
-
return msaa;
}
void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) {
-
ERR_FAIL_INDEX(p_screen_space_aa, SCREEN_SPACE_AA_MAX);
- if (screen_space_aa == p_screen_space_aa)
+ if (screen_space_aa == p_screen_space_aa) {
return;
+ }
screen_space_aa = p_screen_space_aa;
RS::get_singleton()->viewport_set_screen_space_aa(viewport, RS::ViewportScreenSpaceAA(p_screen_space_aa));
}
Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
-
return screen_space_aa;
}
-void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
+void Viewport::set_use_debanding(bool 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);
+}
+
+bool Viewport::is_using_debanding() const {
+ return use_debanding;
+}
+
+void Viewport::set_lod_threshold(float p_pixels) {
+ lod_threshold = p_pixels;
+ RS::get_singleton()->viewport_set_lod_threshold(viewport, lod_threshold);
+}
+
+float Viewport::get_lod_threshold() const {
+ return lod_threshold;
+}
+
+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));
}
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) {
-
snap_controls_to_pixels = p_enable;
}
bool Viewport::is_snap_controls_to_pixels_enabled() const {
-
return snap_controls_to_pixels;
}
+void Viewport::set_snap_2d_transforms_to_pixel(bool p_enable) {
+ snap_2d_transforms_to_pixel = p_enable;
+ RS::get_singleton()->viewport_set_snap_2d_transforms_to_pixel(viewport, snap_2d_transforms_to_pixel);
+}
+
+bool Viewport::is_snap_2d_transforms_to_pixel_enabled() const {
+ return snap_2d_transforms_to_pixel;
+}
+
+void Viewport::set_snap_2d_vertices_to_pixel(bool p_enable) {
+ snap_2d_vertices_to_pixel = p_enable;
+ RS::get_singleton()->viewport_set_snap_2d_vertices_to_pixel(viewport, snap_2d_vertices_to_pixel);
+}
+
+bool Viewport::is_snap_2d_vertices_to_pixel_enabled() const {
+ return snap_2d_vertices_to_pixel;
+}
+
bool Viewport::gui_is_dragging() const {
return gui.dragging;
}
@@ -3253,6 +2906,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;
@@ -3274,15 +2928,29 @@ 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);
+
if (default_canvas_item_texture_filter == p_filter) {
return;
}
default_canvas_item_texture_filter = p_filter;
- _propagate_update_default_filter(this);
+ switch (default_canvas_item_texture_filter) {
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
+ break;
+ default: {
+ }
+ }
}
Viewport::DefaultCanvasItemTextureFilter Viewport::get_default_canvas_item_texture_filter() const {
@@ -3290,36 +2958,31 @@ Viewport::DefaultCanvasItemTextureFilter Viewport::get_default_canvas_item_textu
}
void Viewport::set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat) {
+ ERR_FAIL_INDEX(p_repeat, DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX);
+
if (default_canvas_item_texture_repeat == p_repeat) {
return;
}
- default_canvas_item_texture_repeat = p_repeat;
- _propagate_update_default_repeat(this);
-}
-Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_texture_repeat() const {
- return default_canvas_item_texture_repeat;
-}
-void Viewport::_propagate_update_default_filter(Node *p_node) {
- CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
- if (ci) {
- ci->_update_texture_filter_changed(false);
- }
+ default_canvas_item_texture_repeat = p_repeat;
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _propagate_update_default_filter(p_node->get_child(i));
+ switch (default_canvas_item_texture_repeat) {
+ case DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_repeat(viewport, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_repeat(viewport, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_repeat(viewport, RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
+ break;
+ default: {
+ }
}
}
-void Viewport::_propagate_update_default_repeat(Node *p_node) {
- CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
- if (ci) {
- ci->_update_texture_repeat_changed(false);
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _propagate_update_default_repeat(p_node->get_child(i));
- }
+Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_texture_repeat() const {
+ return default_canvas_item_texture_repeat;
}
DisplayServer::WindowID Viewport::get_window_id() const {
@@ -3338,9 +3001,11 @@ Viewport *Viewport::get_parent_viewport() const {
void Viewport::set_embed_subwindows_hint(bool p_embed) {
gui.embed_subwindows_hint = p_embed;
}
+
bool Viewport::get_embed_subwindows_hint() const {
return gui.embed_subwindows_hint;
}
+
bool Viewport::is_embedding_subwindows() const {
return gui.embed_subwindows_hint;
}
@@ -3361,14 +3026,444 @@ void Viewport::pass_mouse_focus_to(Viewport *p_viewport, Control *p_control) {
}
}
-void Viewport::_bind_methods() {
+void Viewport::set_sdf_oversize(SDFOversize p_sdf_oversize) {
+ ERR_FAIL_INDEX(p_sdf_oversize, SDF_OVERSIZE_MAX);
+ sdf_oversize = p_sdf_oversize;
+ RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale));
+}
+
+Viewport::SDFOversize Viewport::get_sdf_oversize() const {
+ return sdf_oversize;
+}
+
+void Viewport::set_sdf_scale(SDFScale p_sdf_scale) {
+ ERR_FAIL_INDEX(p_sdf_scale, SDF_SCALE_MAX);
+ sdf_scale = p_sdf_scale;
+ RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale));
+}
+
+Viewport::SDFScale Viewport::get_sdf_scale() const {
+ return sdf_scale;
+}
+
+#ifndef _3D_DISABLED
+Listener3D *Viewport::get_listener_3d() const {
+ return listener_3d;
+}
+
+void Viewport::set_as_audio_listener_3d(bool p_enable) {
+ if (p_enable == audio_listener_3d) {
+ return;
+ }
+
+ audio_listener_3d = p_enable;
+ _update_listener_3d();
+}
+
+bool Viewport::is_audio_listener_3d() const {
+ return audio_listener_3d;
+}
+
+void Viewport::_update_listener_3d() {
+ if (AudioServer::get_singleton()) {
+ AudioServer::get_singleton()->notify_listener_changed();
+ }
+}
+
+void Viewport::_listener_transform_3d_changed_notify() {
+}
+
+void Viewport::_listener_3d_set(Listener3D *p_listener) {
+ if (listener_3d == p_listener) {
+ return;
+ }
+
+ listener_3d = p_listener;
+
+ _update_listener_3d();
+ _listener_transform_3d_changed_notify();
+}
+
+bool Viewport::_listener_3d_add(Listener3D *p_listener) {
+ listener_3d_set.insert(p_listener);
+ return listener_3d_set.size() == 1;
+}
+
+void Viewport::_listener_3d_remove(Listener3D *p_listener) {
+ listener_3d_set.erase(p_listener);
+ if (listener_3d == p_listener) {
+ listener_3d = nullptr;
+ }
+}
+
+void Viewport::_listener_3d_make_next_current(Listener3D *p_exclude) {
+ if (listener_3d_set.size() > 0) {
+ for (Set<Listener3D *>::Element *E = listener_3d_set.front(); E; E = E->next()) {
+ if (p_exclude == E->get()) {
+ continue;
+ }
+ if (!E->get()->is_inside_tree()) {
+ continue;
+ }
+ if (listener_3d != nullptr) {
+ return;
+ }
+
+ E->get()->make_current();
+ }
+ } else {
+ // Attempt to reset listener to the camera position.
+ if (camera_3d != nullptr) {
+ _update_listener_3d();
+ _camera_3d_transform_changed_notify();
+ }
+ }
+}
+
+void Viewport::_collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
+ Transform3D object_transform = p_object->get_global_transform();
+ Transform3D camera_transform = p_camera->get_global_transform();
+ ObjectID id = p_object->get_instance_id();
+
+ // Avoid sending the fake event unnecessarily if nothing really changed in the context.
+ if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) {
+ Ref<InputEventMouseMotion> mm = p_input_event;
+ if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
+ return; // Discarded.
+ }
+ }
+ p_object->_input_event_call(camera_3d, p_input_event, p_pos, p_normal, p_shape);
+ physics_last_object_transform = object_transform;
+ physics_last_camera_transform = camera_transform;
+ physics_last_id = id;
+}
+
+Camera3D *Viewport::get_camera_3d() const {
+ return camera_3d;
+}
+
+void Viewport::_camera_3d_transform_changed_notify() {
+}
+
+void Viewport::_camera_3d_set(Camera3D *p_camera) {
+ if (camera_3d == p_camera) {
+ return;
+ }
+
+ if (camera_3d) {
+ camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
+ }
+
+ camera_3d = p_camera;
+
+ if (!camera_3d_override) {
+ if (camera_3d) {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera());
+ } else {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
+ }
+ }
+
+ if (camera_3d) {
+ camera_3d->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
+ }
+
+ _update_listener_3d();
+ _camera_3d_transform_changed_notify();
+}
+
+bool Viewport::_camera_3d_add(Camera3D *p_camera) {
+ camera_3d_set.insert(p_camera);
+ return camera_3d_set.size() == 1;
+}
+
+void Viewport::_camera_3d_remove(Camera3D *p_camera) {
+ camera_3d_set.erase(p_camera);
+ if (camera_3d == p_camera) {
+ camera_3d->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
+ camera_3d = nullptr;
+ }
+}
+
+void Viewport::_camera_3d_make_next_current(Camera3D *p_exclude) {
+ for (Set<Camera3D *>::Element *E = camera_3d_set.front(); E; E = E->next()) {
+ if (p_exclude == E->get()) {
+ continue;
+ }
+ if (!E->get()->is_inside_tree()) {
+ continue;
+ }
+ if (camera_3d != nullptr) {
+ return;
+ }
+
+ E->get()->make_current();
+ }
+}
+
+void Viewport::enable_camera_3d_override(bool p_enable) {
+ if (p_enable == camera_3d_override) {
+ return;
+ }
+
+ if (p_enable) {
+ camera_3d_override.rid = RenderingServer::get_singleton()->camera_create();
+ } else {
+ RenderingServer::get_singleton()->free(camera_3d_override.rid);
+ camera_3d_override.rid = RID();
+ }
+
+ if (p_enable) {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d_override.rid);
+ } else if (camera_3d) {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_3d->get_camera());
+ } else {
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
+ }
+}
+
+void Viewport::set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) {
+ if (camera_3d_override) {
+ if (camera_3d_override.fov == p_fovy_degrees && camera_3d_override.z_near == p_z_near &&
+ camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_PERSPECTIVE) {
+ return;
+ }
+
+ camera_3d_override.fov = p_fovy_degrees;
+ camera_3d_override.z_near = p_z_near;
+ camera_3d_override.z_far = p_z_far;
+ camera_3d_override.projection = Camera3DOverrideData::PROJECTION_PERSPECTIVE;
+
+ RenderingServer::get_singleton()->camera_set_perspective(camera_3d_override.rid, camera_3d_override.fov, camera_3d_override.z_near, camera_3d_override.z_far);
+ }
+}
+
+void Viewport::set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) {
+ if (camera_3d_override) {
+ if (camera_3d_override.size == p_size && camera_3d_override.z_near == p_z_near &&
+ camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) {
+ return;
+ }
+
+ camera_3d_override.size = p_size;
+ camera_3d_override.z_near = p_z_near;
+ camera_3d_override.z_far = p_z_far;
+ camera_3d_override.projection = Camera3DOverrideData::PROJECTION_ORTHOGONAL;
+
+ RenderingServer::get_singleton()->camera_set_orthogonal(camera_3d_override.rid, camera_3d_override.size, camera_3d_override.z_near, camera_3d_override.z_far);
+ }
+}
+
+void Viewport::set_disable_3d(bool p_disable) {
+ disable_3d = p_disable;
+ RenderingServer::get_singleton()->viewport_set_disable_3d(viewport, disable_3d);
+}
+
+bool Viewport::is_3d_disabled() const {
+ return disable_3d;
+}
+
+bool Viewport::is_camera_3d_override_enabled() const {
+ return camera_3d_override;
+}
+
+void Viewport::set_camera_3d_override_transform(const Transform3D &p_transform) {
+ if (camera_3d_override) {
+ camera_3d_override.transform = p_transform;
+ RenderingServer::get_singleton()->camera_set_transform(camera_3d_override.rid, p_transform);
+ }
+}
+
+Transform3D Viewport::get_camera_3d_override_transform() const {
+ if (camera_3d_override) {
+ return camera_3d_override.transform;
+ }
+
+ return Transform3D();
+}
+
+Ref<World3D> Viewport::get_world_3d() const {
+ return world_3d;
+}
+
+Ref<World3D> Viewport::find_world_3d() const {
+ if (own_world_3d.is_valid()) {
+ return own_world_3d;
+ } else if (world_3d.is_valid()) {
+ return world_3d;
+ } else if (parent) {
+ return parent->find_world_3d();
+ } else {
+ return Ref<World3D>();
+ }
+}
+
+void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) {
+ if (world_3d == p_world_3d) {
+ return;
+ }
+
+ if (is_inside_tree()) {
+ _propagate_exit_world_3d(this);
+ }
+
+ if (own_world_3d.is_valid() && world_3d.is_valid()) {
+ world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ }
+
+ world_3d = p_world_3d;
+
+ if (own_world_3d.is_valid()) {
+ if (world_3d.is_valid()) {
+ own_world_3d = world_3d->duplicate();
+ world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ } else {
+ own_world_3d = Ref<World3D>(memnew(World3D));
+ }
+ }
+
+ if (is_inside_tree()) {
+ _propagate_enter_world_3d(this);
+ }
+
+ if (is_inside_tree()) {
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
+ }
+
+ _update_listener_3d();
+}
+void Viewport::_own_world_3d_changed() {
+ ERR_FAIL_COND(world_3d.is_null());
+ ERR_FAIL_COND(own_world_3d.is_null());
+
+ if (is_inside_tree()) {
+ _propagate_exit_world_3d(this);
+ }
+
+ own_world_3d = world_3d->duplicate();
+
+ if (is_inside_tree()) {
+ _propagate_enter_world_3d(this);
+ }
+
+ if (is_inside_tree()) {
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
+ }
+
+ _update_listener_3d();
+}
+
+void Viewport::set_use_own_world_3d(bool p_world_3d) {
+ if (p_world_3d == own_world_3d.is_valid()) {
+ return;
+ }
+
+ if (is_inside_tree()) {
+ _propagate_exit_world_3d(this);
+ }
+
+ if (!p_world_3d) {
+ own_world_3d = Ref<World3D>();
+ if (world_3d.is_valid()) {
+ world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ }
+ } else {
+ if (world_3d.is_valid()) {
+ own_world_3d = world_3d->duplicate();
+ world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed));
+ } else {
+ own_world_3d = Ref<World3D>(memnew(World3D));
+ }
+ }
+
+ if (is_inside_tree()) {
+ _propagate_enter_world_3d(this);
+ }
+
+ if (is_inside_tree()) {
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
+ }
+
+ _update_listener_3d();
+}
+
+bool Viewport::is_using_own_world_3d() const {
+ return own_world_3d.is_valid();
+}
+
+void Viewport::_propagate_enter_world_3d(Node *p_node) {
+ if (p_node != this) {
+ if (!p_node->is_inside_tree()) { //may not have entered scene yet
+ return;
+ }
+
+ if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
+ p_node->notification(Node3D::NOTIFICATION_ENTER_WORLD);
+ } else {
+ Viewport *v = Object::cast_to<Viewport>(p_node);
+ if (v) {
+ if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) {
+ return;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _propagate_enter_world_3d(p_node->get_child(i));
+ }
+}
+
+void Viewport::_propagate_exit_world_3d(Node *p_node) {
+ if (p_node != this) {
+ if (!p_node->is_inside_tree()) { //may have exited scene already
+ return;
+ }
+
+ if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
+ p_node->notification(Node3D::NOTIFICATION_EXIT_WORLD);
+ } else {
+ Viewport *v = Object::cast_to<Viewport>(p_node);
+ if (v) {
+ if (v->world_3d.is_valid() || v->own_world_3d.is_valid()) {
+ return;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _propagate_exit_world_3d(p_node->get_child(i));
+ }
+}
+
+void Viewport::set_use_xr(bool p_use_xr) {
+ use_xr = p_use_xr;
+
+ RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+}
+
+bool Viewport::is_using_xr() {
+ return use_xr;
+}
+
+void Viewport::set_scale_3d(const Scale3D p_scale_3d) {
+ scale_3d = p_scale_3d;
+
+ RS::get_singleton()->viewport_set_scale_3d(viewport, RS::ViewportScale3D(scale_3d));
+}
+
+Viewport::Scale3D Viewport::get_scale_3d() const {
+ return scale_3d;
+}
+
+#endif // _3D_DISABLED
+
+void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_world_2d", "world_2d"), &Viewport::set_world_2d);
ClassDB::bind_method(D_METHOD("get_world_2d"), &Viewport::get_world_2d);
ClassDB::bind_method(D_METHOD("find_world_2d"), &Viewport::find_world_2d);
- ClassDB::bind_method(D_METHOD("set_world", "world"), &Viewport::set_world);
- ClassDB::bind_method(D_METHOD("get_world"), &Viewport::get_world);
- ClassDB::bind_method(D_METHOD("find_world"), &Viewport::find_world);
ClassDB::bind_method(D_METHOD("set_canvas_transform", "xform"), &Viewport::set_canvas_transform);
ClassDB::bind_method(D_METHOD("get_canvas_transform"), &Viewport::get_canvas_transform);
@@ -3387,10 +3482,16 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa);
ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa);
+ 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("get_texture"), &Viewport::get_texture);
@@ -3398,20 +3499,11 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking);
ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid);
- ClassDB::bind_method(D_METHOD("input_text", "text"), &Viewport::input_text);
- ClassDB::bind_method(D_METHOD("input", "event", "in_local_coords"), &Viewport::input, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("unhandled_input", "event", "in_local_coords"), &Viewport::unhandled_input, DEFVAL(false));
-
- ClassDB::bind_method(D_METHOD("update_worlds"), &Viewport::update_worlds);
-
- ClassDB::bind_method(D_METHOD("set_use_own_world", "enable"), &Viewport::set_use_own_world);
- ClassDB::bind_method(D_METHOD("is_using_own_world"), &Viewport::is_using_own_world);
-
- ClassDB::bind_method(D_METHOD("get_camera"), &Viewport::get_camera);
-
- ClassDB::bind_method(D_METHOD("set_as_audio_listener", "enable"), &Viewport::set_as_audio_listener);
- ClassDB::bind_method(D_METHOD("is_audio_listener"), &Viewport::is_audio_listener);
+ ClassDB::bind_method(D_METHOD("push_text_input", "text"), &Viewport::push_text_input);
+ ClassDB::bind_method(D_METHOD("push_input", "event", "in_local_coords"), &Viewport::push_input, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("push_unhandled_input", "event", "in_local_coords"), &Viewport::push_unhandled_input, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_camera_2d"), &Viewport::get_camera_2d);
ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
@@ -3424,16 +3516,24 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input);
ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled);
- ClassDB::bind_method(D_METHOD("_gui_show_tooltip"), &Viewport::_gui_show_tooltip);
- ClassDB::bind_method(D_METHOD("_gui_remove_focus"), &Viewport::_gui_remove_focus);
+ ClassDB::bind_method(D_METHOD("_gui_remove_focus_for_window"), &Viewport::_gui_remove_focus_for_window);
ClassDB::bind_method(D_METHOD("_post_gui_grab_click_focus"), &Viewport::_post_gui_grab_click_focus);
ClassDB::bind_method(D_METHOD("set_shadow_atlas_size", "size"), &Viewport::set_shadow_atlas_size);
ClassDB::bind_method(D_METHOD("get_shadow_atlas_size"), &Viewport::get_shadow_atlas_size);
+ ClassDB::bind_method(D_METHOD("set_shadow_atlas_16_bits", "enable"), &Viewport::set_shadow_atlas_16_bits);
+ ClassDB::bind_method(D_METHOD("get_shadow_atlas_16_bits"), &Viewport::get_shadow_atlas_16_bits);
+
ClassDB::bind_method(D_METHOD("set_snap_controls_to_pixels", "enabled"), &Viewport::set_snap_controls_to_pixels);
ClassDB::bind_method(D_METHOD("is_snap_controls_to_pixels_enabled"), &Viewport::is_snap_controls_to_pixels_enabled);
+ ClassDB::bind_method(D_METHOD("set_snap_2d_transforms_to_pixel", "enabled"), &Viewport::set_snap_2d_transforms_to_pixel);
+ ClassDB::bind_method(D_METHOD("is_snap_2d_transforms_to_pixel_enabled"), &Viewport::is_snap_2d_transforms_to_pixel_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_snap_2d_vertices_to_pixel", "enabled"), &Viewport::set_snap_2d_vertices_to_pixel);
+ ClassDB::bind_method(D_METHOD("is_snap_2d_vertices_to_pixel_enabled"), &Viewport::is_snap_2d_vertices_to_pixel_enabled);
+
ClassDB::bind_method(D_METHOD("set_shadow_atlas_quadrant_subdiv", "quadrant", "subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv);
ClassDB::bind_method(D_METHOD("get_shadow_atlas_quadrant_subdiv", "quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv);
@@ -3453,39 +3553,90 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_repeat", "mode"), &Viewport::set_default_canvas_item_texture_repeat);
ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_repeat"), &Viewport::get_default_canvas_item_texture_repeat);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world"), "set_use_own_world", "is_using_own_world");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world", PROPERTY_HINT_RESOURCE_TYPE, "World"), "set_world", "get_world");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
+ ClassDB::bind_method(D_METHOD("set_sdf_oversize", "oversize"), &Viewport::set_sdf_oversize);
+ ClassDB::bind_method(D_METHOD("get_sdf_oversize"), &Viewport::get_sdf_oversize);
+
+ ClassDB::bind_method(D_METHOD("set_sdf_scale", "scale"), &Viewport::set_sdf_scale);
+ ClassDB::bind_method(D_METHOD("get_sdf_scale"), &Viewport::get_sdf_scale);
+
+ ClassDB::bind_method(D_METHOD("set_lod_threshold", "pixels"), &Viewport::set_lod_threshold);
+ ClassDB::bind_method(D_METHOD("get_lod_threshold"), &Viewport::get_lod_threshold);
+
+ ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking);
+
+#ifndef _3D_DISABLED
+ ClassDB::bind_method(D_METHOD("set_world_3d", "world_3d"), &Viewport::set_world_3d);
+ ClassDB::bind_method(D_METHOD("get_world_3d"), &Viewport::get_world_3d);
+ ClassDB::bind_method(D_METHOD("find_world_3d"), &Viewport::find_world_3d);
+
+ ClassDB::bind_method(D_METHOD("set_use_own_world_3d", "enable"), &Viewport::set_use_own_world_3d);
+ ClassDB::bind_method(D_METHOD("is_using_own_world_3d"), &Viewport::is_using_own_world_3d);
+
+ ClassDB::bind_method(D_METHOD("get_camera_3d"), &Viewport::get_camera_3d);
+ ClassDB::bind_method(D_METHOD("set_as_audio_listener_3d", "enable"), &Viewport::set_as_audio_listener_3d);
+ ClassDB::bind_method(D_METHOD("is_audio_listener_3d"), &Viewport::is_audio_listener_3d);
+
+ ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d);
+ ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled);
+
+ ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr);
+ ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr);
+
+ ClassDB::bind_method(D_METHOD("set_scale_3d", "scale"), &Viewport::set_scale_3d);
+ ClassDB::bind_method(D_METHOD("get_scale_3d"), &Viewport::get_scale_3d);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "scale_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled,75%,50%,33%,25%")), "set_scale_3d", "get_scale_3d");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener_3d", "is_audio_listener_3d");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d");
+#endif // _3D_DISABLED
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", PROPERTY_USAGE_NONE), "set_world_2d", "get_world_2d");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled");
ADD_GROUP("Rendering", "");
- ADD_PROPERTY(PropertyInfo(Variant::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::INT, "msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa", "get_msaa");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling");
+ 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");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener", "is_audio_listener");
ADD_GROUP("Physics", "physics_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking"), "set_physics_object_picking", "get_physics_object_picking");
ADD_GROUP("GUI", "gui_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_disable_input"), "set_disable_input", "is_input_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_snap_controls_to_pixels"), "set_snap_controls_to_pixels", "is_snap_controls_to_pixels_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_embed_subwindows"), "set_embed_subwindows_hint", "get_embed_subwindows_hint");
+ ADD_GROUP("SDF", "sdf_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%"), "set_sdf_oversize", "get_sdf_oversize");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_scale", PROPERTY_HINT_ENUM, "100%,50%,25%"), "set_sdf_scale", "get_sdf_scale");
ADD_GROUP("Shadow Atlas", "shadow_atlas_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_atlas_size"), "set_shadow_atlas_size", "get_shadow_atlas_size");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_atlas_16_bits"), "set_shadow_atlas_16_bits", "get_shadow_atlas_16_bits");
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_0", 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", 0);
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")));
+ BIND_ENUM_CONSTANT(SCALE_3D_DISABLED);
+ BIND_ENUM_CONSTANT(SCALE_3D_75_PERCENT);
+ BIND_ENUM_CONSTANT(SCALE_3D_50_PERCENT);
+ BIND_ENUM_CONSTANT(SCALE_3D_33_PERCENT);
+ BIND_ENUM_CONSTANT(SCALE_3D_25_PERCENT);
+
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_1);
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_4);
@@ -3499,7 +3650,6 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(MSAA_2X);
BIND_ENUM_CONSTANT(MSAA_4X);
BIND_ENUM_CONSTANT(MSAA_8X);
- BIND_ENUM_CONSTANT(MSAA_16X);
BIND_ENUM_CONSTANT(MSAA_MAX);
BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_DISABLED);
@@ -3507,29 +3657,38 @@ 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);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SSAO);
- BIND_ENUM_CONSTANT(DEBUG_DRAW_ROUGHNESS_LIMITER);
BIND_ENUM_CONSTANT(DEBUG_DRAW_PSSM_SPLITS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_DECAL_ATLAS);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_SDFGI);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_SDFGI_PROBES);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_BUFFER);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_DISABLE_LOD);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_OMNI_LIGHTS);
+ 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);
@@ -3541,39 +3700,34 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX);
+
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_100_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_120_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_150_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_200_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_OVERSIZE_MAX);
+
+ BIND_ENUM_CONSTANT(SDF_SCALE_100_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_SCALE_50_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_SCALE_25_PERCENT);
+ BIND_ENUM_CONSTANT(SDF_SCALE_MAX);
}
Viewport::Viewport() {
-
world_2d = Ref<World2D>(memnew(World2D));
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);
- audio_listener = false;
- //internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create();
- audio_listener_2d = false;
- transparent_bg = false;
- parent = nullptr;
- listener = nullptr;
- camera = nullptr;
- override_canvas_transform = false;
- canvas_layers.insert(nullptr); // This eases picking code (interpreted as the canvas of the Viewport)
-
- gen_mipmaps = false;
-
- //clear=true;
+ canvas_layers.insert(nullptr); // This eases picking code (interpreted as the canvas of the Viewport).
- physics_object_picking = false;
- physics_has_last_mousepos = false;
- physics_last_mousepos = Vector2(Math_INF, Math_INF);
+ set_shadow_atlas_size(shadow_atlas_size);
- shadow_atlas_size = 0;
for (int i = 0; i < 4; i++) {
shadow_atlas_quadrant_subdiv[i] = SHADOW_ATLAS_QUADRANT_SUBDIV_MAX;
}
@@ -3582,55 +3736,28 @@ Viewport::Viewport() {
set_shadow_atlas_quadrant_subdiv(2, SHADOW_ATLAS_QUADRANT_SUBDIV_16);
set_shadow_atlas_quadrant_subdiv(3, SHADOW_ATLAS_QUADRANT_SUBDIV_64);
+ set_lod_threshold(lod_threshold);
+
String id = itos(get_instance_id());
input_group = "_vp_input" + id;
gui_input_group = "_vp_gui_input" + id;
unhandled_input_group = "_vp_unhandled_input" + id;
unhandled_key_input_group = "_vp_unhandled_key_input" + id;
- disable_input = false;
-
- //window tooltip
- gui.tooltip_timer = -1;
-
- //gui.tooltip_timer->force_parent_owned();
+ // Window tooltip.
gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5);
ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
- gui.tooltip = nullptr;
- gui.tooltip_label = nullptr;
- gui.drag_preview = nullptr;
- gui.drag_attempted = false;
- gui.canvas_sort_index = 0;
- gui.roots_order_dirty = false;
- gui.mouse_focus = nullptr;
- gui.forced_mouse_focus = false;
- gui.last_mouse_focus = nullptr;
- gui.subwindow_focused = nullptr;
- gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
-
- msaa = MSAA_DISABLED;
- screen_space_aa = SCREEN_SPACE_AA_DISABLED;
- debug_draw = DEBUG_DRAW_DISABLED;
-
- snap_controls_to_pixels = true;
- physics_last_mouse_state.alt = false;
- physics_last_mouse_state.control = false;
- physics_last_mouse_state.shift = false;
- physics_last_mouse_state.meta = false;
- physics_last_mouse_state.mouse_mask = 0;
- local_input_handled = false;
- handle_input_locally = true;
-
- size_allocated = false;
+#ifndef _3D_DISABLED
+ int scale = GLOBAL_GET("rendering/3d/viewport/scale");
+ set_scale_3d((Scale3D)scale);
+#endif // _3D_DISABLED
- default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
- default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
+ set_sdf_oversize(sdf_oversize); // Set to server.
}
Viewport::~Viewport() {
-
- //erase itself from viewport textures
+ // Erase itself from viewport textures.
for (Set<ViewportTexture *>::Element *E = viewport_textures.front(); E; E = E->next()) {
E->get()->vp = nullptr;
}
@@ -3639,34 +3766,23 @@ 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);
}
+
Size2i SubViewport::get_size() const {
return _get_size();
}
void SubViewport::set_size_2d_override(const Size2i &p_size) {
-
_set_size(_get_size(), p_size, Rect2i(), _stretch_transform(), true);
}
-Size2i SubViewport::get_size_2d_override() const {
+Size2i SubViewport::get_size_2d_override() const {
return _get_size_2d_override();
}
void SubViewport::set_size_2d_override_stretch(bool p_enable) {
-
if (p_enable == size_2d_override_stretch) {
return;
}
@@ -3674,28 +3790,26 @@ void SubViewport::set_size_2d_override_stretch(bool p_enable) {
size_2d_override_stretch = p_enable;
_set_size(_get_size(), _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
}
-bool SubViewport::is_size_2d_override_stretch_enabled() const {
+bool SubViewport::is_size_2d_override_stretch_enabled() const {
return size_2d_override_stretch;
}
void SubViewport::set_update_mode(UpdateMode p_mode) {
-
update_mode = p_mode;
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::ViewportUpdateMode(p_mode));
}
-SubViewport::UpdateMode SubViewport::get_update_mode() const {
+SubViewport::UpdateMode SubViewport::get_update_mode() const {
return update_mode;
}
void SubViewport::set_clear_mode(ClearMode p_mode) {
-
clear_mode = p_mode;
RS::get_singleton()->viewport_set_clear_mode(get_viewport_rid(), RS::ViewportClearMode(p_mode));
}
-SubViewport::ClearMode SubViewport::get_clear_mode() const {
+SubViewport::ClearMode SubViewport::get_clear_mode() const {
return clear_mode;
}
@@ -3704,7 +3818,6 @@ DisplayServer::WindowID SubViewport::get_window_id() const {
}
Transform2D SubViewport::_stretch_transform() {
-
Transform2D transform = Transform2D();
Size2i view_size_2d_override = _get_size_2d_override();
if (size_2d_override_stretch && view_size_2d_override.width > 0 && view_size_2d_override.height > 0) {
@@ -3716,7 +3829,6 @@ Transform2D SubViewport::_stretch_transform() {
}
void SubViewport::_notification(int p_what) {
-
if (p_what == NOTIFICATION_ENTER_TREE) {
RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
}
@@ -3726,9 +3838,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);
@@ -3744,7 +3853,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");
@@ -3754,7 +3862,7 @@ void SubViewport::_bind_methods() {
BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);
BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER);
- BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME);
+ BIND_ENUM_CONSTANT(CLEAR_MODE_ONCE);
BIND_ENUM_CONSTANT(UPDATE_DISABLED);
BIND_ENUM_CONSTANT(UPDATE_ONCE);
@@ -3763,12 +3871,6 @@ void SubViewport::_bind_methods() {
BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
}
-SubViewport::SubViewport() {
- xr = false;
- size_2d_override_stretch = false;
- update_mode = UPDATE_WHEN_VISIBLE;
- clear_mode = CLEAR_MODE_ALWAYS;
-}
+SubViewport::SubViewport() {}
-SubViewport::~SubViewport() {
-}
+SubViewport::~SubViewport() {}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 7e2df9fe42..bfb52c4b98 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,33 +31,34 @@
#ifndef VIEWPORT_H
#define VIEWPORT_H
-#include "core/math/transform_2d.h"
#include "scene/main/node.h"
#include "scene/resources/texture.h"
-#include "scene/resources/world_2d.h"
-#include "servers/display_server.h"
-#include "servers/rendering_server.h"
+#ifndef _3D_DISABLED
class Camera3D;
-class Camera2D;
+class CollisionObject3D;
class Listener3D;
-class Control;
+class World3D;
+#endif // _3D_DISABLED
+
+class Listener2D;
+class Camera2D;
class CanvasItem;
class CanvasLayer;
-class Panel;
+class Control;
class Label;
-class Timer;
+class SceneTreeTimer;
class Viewport;
-class CollisionObject3D;
+class Window;
+class World2D;
class ViewportTexture : public Texture2D {
-
GDCLASS(ViewportTexture, Texture2D);
NodePath path;
friend class Viewport;
- Viewport *vp;
+ Viewport *vp = nullptr;
mutable RID proxy_ph;
mutable RID proxy;
@@ -69,26 +70,33 @@ public:
void set_viewport_path_in_scene(const NodePath &p_path);
NodePath get_viewport_path_in_scene() const;
- virtual void setup_local_to_scene();
+ virtual void setup_local_to_scene() override;
- virtual int get_width() const;
- virtual int get_height() const;
- virtual Size2 get_size() const;
- virtual RID get_rid() const;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual Size2 get_size() const override;
+ virtual RID get_rid() const override;
- virtual bool has_alpha() const;
+ virtual bool has_alpha() const override;
- virtual Ref<Image> get_data() const;
+ virtual Ref<Image> get_image() const override;
ViewportTexture();
~ViewportTexture();
};
class Viewport : public Node {
-
GDCLASS(Viewport, Node);
public:
+ enum Scale3D {
+ SCALE_3D_DISABLED,
+ SCALE_3D_75_PERCENT,
+ SCALE_3D_50_PERCENT,
+ SCALE_3D_33_PERCENT,
+ SCALE_3D_25_PERCENT
+ };
+
enum ShadowAtlasQuadrantSubdiv {
SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED,
SHADOW_ATLAS_QUADRANT_SUBDIV_1,
@@ -105,7 +113,7 @@ public:
MSAA_2X,
MSAA_4X,
MSAA_8X,
- MSAA_16X,
+ // 16x MSAA is not supported due to its high cost and driver bugs.
MSAA_MAX
};
@@ -117,14 +125,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,
@@ -132,16 +143,24 @@ 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,
DEBUG_DRAW_SSAO,
- DEBUG_DRAW_ROUGHNESS_LIMITER,
DEBUG_DRAW_PSSM_SPLITS,
- DEBUG_DRAW_DECAL_ATLAS
+ DEBUG_DRAW_DECAL_ATLAS,
+ DEBUG_DRAW_SDFGI,
+ DEBUG_DRAW_SDFGI_PROBES,
+ DEBUG_DRAW_GI_BUFFER,
+ DEBUG_DRAW_DISABLE_LOD,
+ DEBUG_DRAW_CLUSTER_OMNI_LIGHTS,
+ DEBUG_DRAW_CLUSTER_SPOT_LIGHTS,
+ DEBUG_DRAW_CLUSTER_DECALS,
+ DEBUG_DRAW_CLUSTER_REFLECTION_PROBES,
+ DEBUG_DRAW_OCCLUDERS,
};
enum DefaultCanvasItemTextureFilter {
@@ -159,6 +178,21 @@ public:
DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX,
};
+ enum SDFOversize {
+ SDF_OVERSIZE_100_PERCENT,
+ SDF_OVERSIZE_120_PERCENT,
+ SDF_OVERSIZE_150_PERCENT,
+ SDF_OVERSIZE_200_PERCENT,
+ SDF_OVERSIZE_MAX
+ };
+
+ enum SDFScale {
+ SDF_SCALE_100_PERCENT,
+ SDF_SCALE_50_PERCENT,
+ SDF_SCALE_25_PERCENT,
+ SDF_SCALE_MAX
+ };
+
enum {
SUBWINDOW_CANVAS_LAYER = 1024
};
@@ -166,53 +200,29 @@ public:
private:
friend class ViewportTexture;
- Viewport *parent;
-
- Listener3D *listener;
- Set<Listener3D *> listeners;
+ Viewport *parent = nullptr;
- struct CameraOverrideData {
- Transform transform;
- enum Projection {
- PROJECTION_PERSPECTIVE,
- PROJECTION_ORTHOGONAL
- };
- Projection projection;
- float fov;
- float size;
- float z_near;
- float z_far;
- RID rid;
-
- operator bool() const {
- return rid != RID();
- }
- } camera_override;
-
- Camera3D *camera;
- Set<Camera3D *> cameras;
+ Listener2D *listener_2d = nullptr;
+ Camera2D *camera_2d = nullptr;
Set<CanvasLayer *> canvas_layers;
RID viewport;
RID current_canvas;
RID subwindow_canvas;
- bool audio_listener;
- RID internal_listener;
-
- bool audio_listener_2d;
+ bool audio_listener_2d = false;
RID internal_listener_2d;
- bool override_canvas_transform;
+ bool override_canvas_transform = false;
Transform2D canvas_transform_override;
Transform2D canvas_transform;
Transform2D global_canvas_transform;
Transform2D stretch_transform;
- Size2i size;
+ Size2i size = Size2i(512, 512);
Size2i size_2d_override;
- bool size_allocated;
+ bool size_allocated = false;
RID contact_2d_debug;
RID contact_3d_debug_multimesh;
@@ -220,41 +230,43 @@ private:
Rect2 last_vp_rect;
- bool transparent_bg;
+ bool transparent_bg = false;
bool filter;
- bool gen_mipmaps;
+ bool gen_mipmaps = false;
- bool snap_controls_to_pixels;
+ bool snap_controls_to_pixels = true;
+ bool snap_2d_transforms_to_pixel = false;
+ bool snap_2d_vertices_to_pixel = false;
- bool physics_object_picking;
+ bool physics_object_picking = false;
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;
- Vector2 physics_last_mousepos;
+ bool physics_has_last_mousepos = false;
+ Vector2 physics_last_mousepos = Vector2(INFINITY, INFINITY);
struct {
-
- bool alt;
- bool control;
- bool shift;
- bool meta;
- int mouse_mask;
+ bool alt = false;
+ bool control = false;
+ bool shift = false;
+ bool meta = false;
+ int mouse_mask = 0;
} physics_last_mouse_state;
- void _collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
-
- bool handle_input_locally;
- bool local_input_handled;
+ 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;
- Ref<World3D> own_world;
Rect2i to_screen_rect;
StringName input_group;
@@ -262,27 +274,34 @@ private:
StringName unhandled_input_group;
StringName unhandled_key_input_group;
- void _update_listener();
void _update_listener_2d();
- void _propagate_enter_world(Node *p_node);
- void _propagate_exit_world(Node *p_node);
+ bool disable_3d = false;
+
void _propagate_viewport_notification(Node *p_node, int p_what);
void _update_global_transform();
RID texture_rid;
- DebugDraw debug_draw;
+ DebugDraw debug_draw = DEBUG_DRAW_DISABLED;
- int shadow_atlas_size;
+ int shadow_atlas_size = 2048;
+ bool shadow_atlas_16_bits = true;
ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4];
- MSAA msaa;
- ScreenSpaceAA screen_space_aa;
+ MSAA msaa = MSAA_DISABLED;
+ 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;
+ SDFOversize sdf_oversize = SDF_OVERSIZE_120_PERCENT;
+ SDFScale sdf_scale = SDF_SCALE_50_PERCENT;
+
enum SubWindowDrag {
SUB_WINDOW_DRAG_DISABLED,
SUB_WINDOW_DRAG_MOVE,
@@ -304,75 +323,67 @@ private:
};
struct SubWindow {
- Window *window;
+ Window *window = nullptr;
RID canvas_item;
};
struct GUI {
// info used when this is a window
- bool forced_mouse_focus; //used for menu buttons
- bool key_event_accepted;
- Control *mouse_focus;
- Control *last_mouse_focus;
- Control *mouse_click_grabber;
- int mouse_focus_mask;
- Control *key_focus;
- Control *mouse_over;
- Control *drag_mouse_over;
+ bool forced_mouse_focus = false; //used for menu buttons
+ bool key_event_accepted = false;
+ Control *mouse_focus = nullptr;
+ Control *last_mouse_focus = nullptr;
+ Control *mouse_click_grabber = nullptr;
+ int mouse_focus_mask = 0;
+ Control *key_focus = nullptr;
+ Control *mouse_over = nullptr;
+ Control *drag_mouse_over = nullptr;
Vector2 drag_mouse_over_pos;
- Control *tooltip;
- Window *tooltip_popup;
- Label *tooltip_label;
+ Control *tooltip_control = nullptr;
+ Window *tooltip_popup = nullptr;
+ Label *tooltip_label = nullptr;
Point2 tooltip_pos;
Point2 last_mouse_pos;
Point2 drag_accum;
- bool drag_attempted;
+ bool drag_attempted = false;
Variant drag_data;
- Control *drag_preview;
- float tooltip_timer;
- float tooltip_delay;
+ ObjectID drag_preview_id;
+ Ref<SceneTreeTimer> tooltip_timer;
+ double tooltip_delay = 0.0;
Transform2D focus_inv_xform;
- bool roots_order_dirty;
+ bool roots_order_dirty = false;
List<Control *> roots;
- int canvas_sort_index; //for sorting items with canvas as root
- bool dragging;
- bool embed_subwindows_hint;
- bool embedding_subwindows;
+ int canvas_sort_index = 0; //for sorting items with canvas as root
+ bool dragging = false;
+ bool embed_subwindows_hint = false;
+ bool embedding_subwindows = false;
- Window *subwindow_focused;
- SubWindowDrag subwindow_drag;
+ Window *subwindow_focused = nullptr;
+ SubWindowDrag subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
Vector2 subwindow_drag_from;
Vector2 subwindow_drag_pos;
Rect2i subwindow_drag_close_rect;
- bool subwindow_drag_close_inside;
+ bool subwindow_drag_close_inside = false;
SubWindowResize subwindow_resize_mode;
Rect2i subwindow_resize_from_rect;
Vector<SubWindow> sub_windows;
-
- GUI();
} gui;
- DefaultCanvasItemTextureFilter default_canvas_item_texture_filter;
- DefaultCanvasItemTextureRepeat default_canvas_item_texture_repeat;
+ DefaultCanvasItemTextureFilter default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
+ DefaultCanvasItemTextureRepeat default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
- void _propagate_update_default_filter(Node *p_node);
- void _propagate_update_default_repeat(Node *p_node);
-
- bool disable_input;
+ bool disable_input = false;
void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input);
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);
@@ -383,16 +394,18 @@ private:
void _gui_remove_root_control(List<Control *>::Element *RI);
- String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = nullptr);
+ String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_tooltip_owner = nullptr);
void _gui_cancel_tooltip();
void _gui_show_tooltip();
void _gui_remove_control(Control *p_control);
- void _gui_hid_control(Control *p_control);
+ void _gui_hide_control(Control *p_control);
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();
void _gui_unfocus_control(Control *p_control);
bool _gui_control_has_focus(const Control *p_control);
@@ -405,33 +418,24 @@ private:
bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check);
- friend class Listener3D;
- void _listener_transform_changed_notify();
- void _listener_set(Listener3D *p_listener);
- bool _listener_add(Listener3D *p_listener); //true if first
- void _listener_remove(Listener3D *p_listener);
- void _listener_make_next_current(Listener3D *p_exclude);
+ friend class Listener2D;
+ void _listener_2d_set(Listener2D *p_listener);
+ void _listener_2d_remove(Listener2D *p_listener);
- friend class Camera3D;
- void _camera_transform_changed_notify();
- void _camera_set(Camera3D *p_camera);
- bool _camera_add(Camera3D *p_camera); //true if first
- void _camera_remove(Camera3D *p_camera);
- void _camera_make_next_current(Camera3D *p_exclude);
+ friend class Camera2D;
+ void _camera_2d_set(Camera2D *p_camera_2d);
friend class CanvasLayer;
void _canvas_layer_add(CanvasLayer *p_canvas_layer);
void _canvas_layer_remove(CanvasLayer *p_canvas_layer);
void _drop_mouse_focus();
- void _drop_physics_mouseover();
+ void _drop_physics_mouseover(bool p_paused_only = false);
void _update_canvas_items(Node *p_node);
void _gui_set_root_order_dirty();
- void _own_world_changed();
-
friend class Window;
void _sub_window_update_order();
@@ -442,6 +446,9 @@ private:
bool _sub_windows_forward_input(const Ref<InputEvent> &p_event);
SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point);
+ virtual bool _can_consume_input_events() const { return true; }
+ uint64_t event_count = 0;
+
protected:
void _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated);
@@ -450,25 +457,14 @@ protected:
bool _is_size_allocated() const;
void _notification(int p_what);
+ void _process_picking();
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const;
public:
- Listener3D *get_listener() const;
- Camera3D *get_camera() const;
-
- void enable_camera_override(bool p_enable);
- bool is_camera_override_enabled() const;
-
- void set_camera_override_transform(const Transform &p_transform);
- Transform get_camera_override_transform() const;
-
- void set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
- void set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far);
-
- void set_as_audio_listener(bool p_enable);
- bool is_audio_listener() const;
+ uint64_t get_processed_events_count() const { return event_count; }
+ Listener2D *get_listener_2d() const;
+ Camera2D *get_camera_2d() const;
void set_as_audio_listener_2d(bool p_enable);
bool is_audio_listener_2d() const;
@@ -477,11 +473,7 @@ public:
Rect2 get_visible_rect() const;
RID get_viewport_rid() const;
- void set_world(const Ref<World3D> &p_world);
void set_world_2d(const Ref<World2D> &p_world_2d);
- Ref<World3D> get_world() const;
- Ref<World3D> find_world() const;
-
Ref<World2D> get_world_2d() const;
Ref<World2D> find_world_2d() const;
@@ -507,6 +499,9 @@ public:
void set_shadow_atlas_size(int p_size);
int get_shadow_atlas_size() const;
+ void set_shadow_atlas_16_bits(bool p_16_bits);
+ bool get_shadow_atlas_16_bits() const;
+
void set_shadow_atlas_quadrant_subdiv(int p_quadrant, ShadowAtlasQuadrantSubdiv p_subdiv);
ShadowAtlasQuadrantSubdiv get_shadow_atlas_quadrant_subdiv(int p_quadrant) const;
@@ -516,15 +511,21 @@ public:
void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa);
ScreenSpaceAA get_screen_space_aa() const;
+ void set_use_debanding(bool p_use_debanding);
+ bool is_using_debanding() const;
+
+ 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;
- void set_use_own_world(bool p_world);
- bool is_using_own_world() const;
-
- void input_text(const String &p_text);
- void input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
- void unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
+ void push_text_input(const String &p_text);
+ void push_input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
+ void push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
void set_disable_input(bool p_disable);
bool is_input_disabled() const;
@@ -540,16 +541,22 @@ public:
void gui_reset_canvas_sort_index();
int gui_get_canvas_sort_index();
- virtual String get_configuration_warning() const;
+ 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;
+ void set_snap_2d_transforms_to_pixel(bool p_enable);
+ bool is_snap_2d_transforms_to_pixel_enabled() const;
+
+ void set_snap_2d_vertices_to_pixel(bool p_enable);
+ bool is_snap_2d_vertices_to_pixel_enabled() const;
+
void set_input_as_handled();
bool is_input_handled() const;
@@ -558,6 +565,14 @@ 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;
+
+ void set_sdf_scale(SDFScale p_sdf_scale);
+ SDFScale get_sdf_scale() const;
+
void set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter);
DefaultCanvasItemTextureFilter get_default_canvas_item_texture_filter() const;
@@ -571,23 +586,100 @@ public:
bool is_embedding_subwindows() const;
Viewport *get_parent_viewport() const;
+ Window *get_base_window() const;
void pass_mouse_focus_to(Viewport *p_viewport, Control *p_control);
+#ifndef _3D_DISABLED
+ bool use_xr = false;
+ Scale3D scale_3d = SCALE_3D_DISABLED;
+ friend class Listener3D;
+ Listener3D *listener_3d = nullptr;
+ Set<Listener3D *> listener_3d_set;
+ bool audio_listener_3d = false;
+ RID internal_listener_3d;
+ Listener3D *get_listener_3d() const;
+ void set_as_audio_listener_3d(bool p_enable);
+ bool is_audio_listener_3d() const;
+ void _update_listener_3d();
+ void _listener_transform_3d_changed_notify();
+ void _listener_3d_set(Listener3D *p_listener);
+ bool _listener_3d_add(Listener3D *p_listener); //true if first
+ void _listener_3d_remove(Listener3D *p_listener);
+ void _listener_3d_make_next_current(Listener3D *p_exclude);
+
+ void _collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
+
+ struct Camera3DOverrideData {
+ Transform3D transform;
+ enum Projection {
+ PROJECTION_PERSPECTIVE,
+ PROJECTION_ORTHOGONAL
+ };
+ Projection projection = Projection::PROJECTION_PERSPECTIVE;
+ real_t fov = 0.0;
+ real_t size = 0.0;
+ real_t z_near = 0.0;
+ real_t z_far = 0.0;
+ RID rid;
+
+ operator bool() const {
+ return rid != RID();
+ }
+ } camera_3d_override;
+
+ friend class Camera3D;
+ Camera3D *camera_3d = nullptr;
+ Set<Camera3D *> camera_3d_set;
+ Camera3D *get_camera_3d() const;
+ void _camera_3d_transform_changed_notify();
+ void _camera_3d_set(Camera3D *p_camera);
+ bool _camera_3d_add(Camera3D *p_camera); //true if first
+ void _camera_3d_remove(Camera3D *p_camera);
+ void _camera_3d_make_next_current(Camera3D *p_exclude);
+
+ void enable_camera_3d_override(bool p_enable);
+ bool is_camera_3d_override_enabled() const;
+
+ void set_camera_3d_override_transform(const Transform3D &p_transform);
+ Transform3D get_camera_3d_override_transform() const;
+
+ void set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far);
+ void set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far);
+
+ void set_disable_3d(bool p_disable);
+ bool is_3d_disabled() const;
+
+ Ref<World3D> world_3d;
+ Ref<World3D> own_world_3d;
+ void set_world_3d(const Ref<World3D> &p_world_3d);
+ Ref<World3D> get_world_3d() const;
+ Ref<World3D> find_world_3d() const;
+ void _own_world_3d_changed();
+ void set_use_own_world_3d(bool p_world_3d);
+ bool is_using_own_world_3d() const;
+ void _propagate_enter_world_3d(Node *p_node);
+ void _propagate_exit_world_3d(Node *p_node);
+
+ void set_use_xr(bool p_use_xr);
+ bool is_using_xr();
+
+ void set_scale_3d(const Scale3D p_scale_3d);
+ Scale3D get_scale_3d() const;
+#endif // _3D_DISABLED
+
Viewport();
~Viewport();
};
class SubViewport : public Viewport {
-
GDCLASS(SubViewport, Viewport);
public:
enum ClearMode {
-
CLEAR_MODE_ALWAYS,
CLEAR_MODE_NEVER,
- CLEAR_MODE_ONLY_NEXT_FRAME
+ CLEAR_MODE_ONCE
};
enum UpdateMode {
@@ -599,14 +691,13 @@ public:
};
private:
- UpdateMode update_mode;
- ClearMode clear_mode;
- bool xr;
- bool size_2d_override_stretch;
+ UpdateMode update_mode = UPDATE_WHEN_VISIBLE;
+ ClearMode clear_mode = CLEAR_MODE_ALWAYS;
+ bool size_2d_override_stretch = false;
protected:
static void _bind_methods();
- virtual DisplayServer::WindowID get_window_id() const;
+ virtual DisplayServer::WindowID get_window_id() const override;
Transform2D _stretch_transform();
void _notification(int p_what);
@@ -617,9 +708,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;
@@ -636,9 +724,13 @@ VARIANT_ENUM_CAST(SubViewport::UpdateMode);
VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv);
VARIANT_ENUM_CAST(Viewport::MSAA);
VARIANT_ENUM_CAST(Viewport::ScreenSpaceAA);
+VARIANT_ENUM_CAST(Viewport::Scale3D);
VARIANT_ENUM_CAST(Viewport::DebugDraw);
+VARIANT_ENUM_CAST(Viewport::SDFScale);
+VARIANT_ENUM_CAST(Viewport::SDFOversize);
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 19954299de..ca5a3915d0 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,9 +31,8 @@
#include "window.h"
#include "core/debugger/engine_debugger.h"
-#include "core/os/keyboard.h"
+#include "core/string/translation.h"
#include "scene/gui/control.h"
-#include "scene/resources/dynamic_font.h"
#include "scene/scene_string_names.h"
void Window::set_title(const String &p_title) {
@@ -41,22 +40,23 @@ void Window::set_title(const String &p_title) {
if (embedder) {
embedder->_sub_window_update(this);
-
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-
- DisplayServer::get_singleton()->window_set_title(p_title, window_id);
+ DisplayServer::get_singleton()->window_set_title(atr(p_title), window_id);
}
}
+
String Window::get_title() const {
return title;
}
void Window::set_current_screen(int p_screen) {
current_screen = p_screen;
- if (window_id == DisplayServer::INVALID_WINDOW_ID)
+ if (window_id == DisplayServer::INVALID_WINDOW_ID) {
return;
+ }
DisplayServer::get_singleton()->window_set_current_screen(p_screen, window_id);
}
+
int Window::get_current_screen() const {
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
current_screen = DisplayServer::get_singleton()->window_get_current_screen(window_id);
@@ -65,17 +65,16 @@ int Window::get_current_screen() const {
}
void Window::set_position(const Point2i &p_position) {
-
position = p_position;
if (embedder) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-
DisplayServer::get_singleton()->window_set_position(p_position, window_id);
}
}
+
Point2i Window::get_position() const {
return position;
}
@@ -84,13 +83,12 @@ void Window::set_size(const Size2i &p_size) {
size = p_size;
_update_window_size();
}
-Size2i Window::get_size() const {
+Size2i Window::get_size() const {
return size;
}
Size2i Window::get_real_size() const {
-
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
return DisplayServer::get_singleton()->window_get_real_size(window_id);
}
@@ -114,7 +112,7 @@ Size2i Window::get_max_size() const {
void Window::set_min_size(const Size2i &p_min_size) {
min_size = p_min_size;
- if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ if (!wrap_controls && window_id != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_min_size(min_size, window_id);
}
_update_window_size();
@@ -128,20 +126,17 @@ Size2i Window::get_min_size() const {
}
void Window::set_mode(Mode p_mode) {
-
mode = p_mode;
if (embedder) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-
DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id);
}
}
Window::Mode Window::get_mode() const {
-
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id);
}
@@ -156,7 +151,6 @@ void Window::set_flag(Flags p_flag, bool p_enabled) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
}
}
@@ -181,8 +175,8 @@ void Window::request_attention() {
DisplayServer::get_singleton()->window_request_attention(window_id);
}
}
-void Window::move_to_foreground() {
+void Window::move_to_foreground() {
if (embedder) {
embedder->_sub_window_grab_focus(this);
@@ -207,6 +201,7 @@ void Window::set_ime_active(bool p_active) {
DisplayServer::get_singleton()->window_set_ime_active(p_active, window_id);
}
}
+
void Window::set_ime_position(const Point2i &p_pos) {
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_ime_position(p_pos, window_id);
@@ -229,12 +224,13 @@ void Window::_make_window() {
}
}
- window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size));
+ DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID);
+ window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size));
ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id);
DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
DisplayServer::get_singleton()->window_set_min_size(min_size, window_id);
- DisplayServer::get_singleton()->window_set_title(title, window_id);
+ DisplayServer::get_singleton()->window_set_title(atr(title), window_id);
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
_update_window_size();
@@ -249,10 +245,13 @@ void Window::_make_window() {
}
}
+ _update_window_callbacks();
+
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
+ DisplayServer::get_singleton()->show_window(window_id);
}
-void Window::_update_from_window() {
+void Window::_update_from_window() {
ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id);
for (int i = 0; i < FLAG_MAX; i++) {
@@ -283,7 +282,6 @@ void Window::_clear_window() {
}
void Window::_rect_changed_callback(const Rect2i &p_callback) {
-
//we must always accept this as the truth
if (size == p_callback.size && position == p_callback.position) {
return;
@@ -302,48 +300,49 @@ void Window::_propagate_window_notification(Node *p_node, int p_notification) {
Node *child = p_node->get_child(i);
Window *window = Object::cast_to<Window>(child);
if (window) {
- break;
+ continue;
}
_propagate_window_notification(child, p_notification);
}
}
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_FOCUS_IN);
- emit_signal("focus_entered");
+ _propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_IN);
+ emit_signal(SNAME("focus_entered"));
} break;
case DisplayServer::WINDOW_EVENT_FOCUS_OUT: {
focused = false;
- _propagate_window_notification(this, NOTIFICATION_WM_FOCUS_OUT);
- emit_signal("focus_exited");
+ _propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_OUT);
+ 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;
}
}
@@ -351,12 +350,12 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
void Window::show() {
set_visible(true);
}
+
void Window::hide() {
set_visible(false);
}
void Window::set_visible(bool p_visible) {
-
if (visible == p_visible) {
return;
}
@@ -381,7 +380,6 @@ void Window::set_visible(bool p_visible) {
}
if (p_visible && window_id == DisplayServer::INVALID_WINDOW_ID) {
_make_window();
- _update_window_callbacks();
}
} else {
if (visible) {
@@ -403,6 +401,18 @@ void Window::set_visible(bool p_visible) {
emit_signal(SceneStringNames::get_singleton()->visibility_changed);
RS::get_singleton()->viewport_set_active(get_viewport_rid(), visible);
+
+ //update transient exclusive
+ if (transient_parent) {
+ if (exclusive && visible) {
+ ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
+ transient_parent->exclusive_child = this;
+ } else {
+ if (transient_parent->exclusive_child == this) {
+ transient_parent->exclusive_child = nullptr;
+ }
+ }
+ }
}
void Window::_clear_transient() {
@@ -473,12 +483,12 @@ void Window::set_transient(bool p_transient) {
_clear_transient();
}
}
+
bool Window::is_transient() const {
return transient;
}
void Window::set_exclusive(bool p_exclusive) {
-
if (exclusive == p_exclusive) {
return;
}
@@ -506,7 +516,6 @@ bool Window::is_visible() const {
}
void Window::_update_window_size() {
-
Size2i size_limit;
if (wrap_controls) {
size_limit = get_contents_minimum_size();
@@ -518,11 +527,11 @@ void Window::_update_window_size() {
size.x = MAX(size_limit.x, size.x);
size.y = MAX(size_limit.y, size.y);
- if (max_size.x > 0 && max_size.x > min_size.x && max_size.x > size.x) {
+ if (max_size.x > 0 && max_size.x > min_size.x && size.x > max_size.x) {
size.x = max_size.x;
}
- if (max_size.y > 0 && max_size.y > min_size.y && max_size.y > size.y) {
+ if (max_size.y > 0 && max_size.y > min_size.y && size.y > max_size.y) {
size.y = max_size.y;
}
@@ -530,11 +539,13 @@ 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
_update_viewport_size();
}
+
void Window::_update_viewport_size() {
//update the viewport part
@@ -545,12 +556,10 @@ void Window::_update_viewport_size() {
float font_oversampling = 1.0;
if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) {
-
stretch_transform = Transform2D();
final_size = size;
} else {
-
//actual screen video mode
Size2 video_mode = size;
Size2 desired_res = content_scale_size;
@@ -569,7 +578,6 @@ void Window::_update_viewport_size() {
// screen ratio is smaller vertically
if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_HEIGHT || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) {
-
//will stretch horizontally
viewport_size.x = desired_res.y * video_mode_aspect;
viewport_size.y = desired_res.y;
@@ -584,7 +592,6 @@ void Window::_update_viewport_size() {
} else {
//screen ratio is smaller horizontally
if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_WIDTH || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) {
-
//will stretch horizontally
viewport_size.x = desired_res.x;
viewport_size.y = desired_res.x / video_mode_aspect;
@@ -621,28 +628,25 @@ void Window::_update_viewport_size() {
// Already handled above
//_update_font_oversampling(1.0);
} break;
- case CONTENT_SCALE_MODE_OBJECTS: {
-
+ case CONTENT_SCALE_MODE_CANVAS_ITEMS: {
final_size = screen_size;
final_size_override = viewport_size;
attach_to_screen_rect = Rect2(margin, screen_size);
font_oversampling = screen_size.x / viewport_size.x;
- } break;
- case CONTENT_SCALE_MODE_PIXELS: {
+ Size2 scale = Vector2(screen_size) / Vector2(final_size_override);
+ stretch_transform.scale(scale);
+
+ } break;
+ case CONTENT_SCALE_MODE_VIEWPORT: {
final_size = viewport_size;
attach_to_screen_rect = Rect2(margin, screen_size);
} break;
}
-
- Size2 scale = size / (Vector2(final_size) + margin * 2);
- stretch_transform.scale(scale);
- stretch_transform.elements[2] = margin * scale;
}
bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr);
-
_set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform, allocate);
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
@@ -652,14 +656,11 @@ void Window::_update_viewport_size() {
}
if (window_id == DisplayServer::MAIN_WINDOW_ID) {
-
if (!use_font_oversampling) {
font_oversampling = 1.0;
}
- if (DynamicFontAtSize::font_oversampling != font_oversampling) {
-
- DynamicFontAtSize::font_oversampling = font_oversampling;
- DynamicFont::update_oversampling();
+ if (TS->font_get_global_oversampling() != font_oversampling) {
+ TS->font_set_global_oversampling(font_oversampling);
}
}
@@ -679,11 +680,9 @@ void Window::_update_window_callbacks() {
}
Viewport *Window::_get_embedder() const {
-
Viewport *vp = get_parent_viewport();
while (vp) {
-
if (vp->is_embedding_subwindows()) {
return vp;
}
@@ -698,97 +697,98 @@ Viewport *Window::_get_embedder() const {
}
void Window::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
-
- bool embedded = false;
- {
-
- embedder = _get_embedder();
-
- if (embedder) {
- embedded = true;
-
- if (!visible) {
- embedder = nullptr; //not yet since not visible
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ bool embedded = false;
+ {
+ embedder = _get_embedder();
+
+ if (embedder) {
+ embedded = true;
+
+ if (!visible) {
+ embedder = nullptr; //not yet since not visible
+ }
}
}
- }
-
- if (embedded) {
- //create as embedded
- if (embedder) {
- embedder->_sub_window_register(this);
- RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
- _update_window_size();
- }
- } else {
- if (get_parent() == nullptr) {
- //it's the root window!
- visible = true; //always visible
- window_id = DisplayServer::MAIN_WINDOW_ID;
- DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
- _update_from_window();
- //since this window already exists (created on start), we must update pos and size from it
- {
- position = DisplayServer::get_singleton()->window_get_position(window_id);
- size = DisplayServer::get_singleton()->window_get_size(window_id);
+ if (embedded) {
+ //create as embedded
+ if (embedder) {
+ embedder->_sub_window_register(this);
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
+ _update_window_size();
}
- _update_viewport_size(); //then feed back to the viewport
- _update_window_callbacks();
- RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
+
} else {
- //create
- if (visible) {
- _make_window();
+ if (get_parent() == nullptr) {
+ //it's the root window!
+ visible = true; //always visible
+ window_id = DisplayServer::MAIN_WINDOW_ID;
+ DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
+ _update_from_window();
+ //since this window already exists (created on start), we must update pos and size from it
+ {
+ position = DisplayServer::get_singleton()->window_get_position(window_id);
+ size = DisplayServer::get_singleton()->window_get_size(window_id);
+ }
+ _update_viewport_size(); //then feed back to the viewport
_update_window_callbacks();
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
+ } else {
+ //create
+ if (visible) {
+ _make_window();
+ }
}
}
- }
-
- if (transient) {
- _make_transient();
- }
- if (visible) {
- notification(NOTIFICATION_VISIBILITY_CHANGED);
- emit_signal(SceneStringNames::get_singleton()->visibility_changed);
- RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
- }
- }
-
- if (p_what == NOTIFICATION_READY) {
-
- if (wrap_controls) {
- _update_child_controls();
- }
- }
- if (p_what == NOTIFICATION_EXIT_TREE) {
-
- if (transient) {
- _clear_transient();
- }
-
- if (!is_embedded() && window_id != DisplayServer::INVALID_WINDOW_ID) {
-
- if (window_id == DisplayServer::MAIN_WINDOW_ID) {
+ if (transient) {
+ _make_transient();
+ }
+ if (visible) {
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+ emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
+ }
+ } break;
+ case NOTIFICATION_READY: {
+ if (wrap_controls) {
+ _update_child_controls();
+ }
+ } break;
+ case NOTIFICATION_TRANSLATION_CHANGED: {
+ if (embedder) {
+ embedder->_sub_window_update(this);
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_title(atr(title), window_id);
+ }
- RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
- _update_window_callbacks();
- } else {
- _clear_window();
+ child_controls_changed();
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ if (transient) {
+ _clear_transient();
}
- } else {
- if (embedder) {
- embedder->_sub_window_remove(this);
- embedder = nullptr;
- RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+ if (!is_embedded() && window_id != DisplayServer::INVALID_WINDOW_ID) {
+ if (window_id == DisplayServer::MAIN_WINDOW_ID) {
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+ _update_window_callbacks();
+ } else {
+ _clear_window();
+ }
+ } else {
+ if (embedder) {
+ embedder->_sub_window_remove(this);
+ embedder = nullptr;
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+ }
+ _update_viewport_size(); //called by clear and make, which does not happen here
}
- _update_viewport_size(); //called by clear and make, which does not happen here
- }
- RS::get_singleton()->viewport_set_active(get_viewport_rid(), false);
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), false);
+ } break;
}
}
@@ -807,6 +807,7 @@ void Window::set_content_scale_mode(ContentScaleMode p_mode) {
content_scale_mode = p_mode;
_update_viewport_size();
}
+
Window::ContentScaleMode Window::get_content_scale_mode() const {
return content_scale_mode;
}
@@ -815,6 +816,7 @@ void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) {
content_scale_aspect = p_aspect;
_update_viewport_size();
}
+
Window::ContentScaleAspect Window::get_content_scale_aspect() const {
return content_scale_aspect;
}
@@ -826,11 +828,15 @@ void Window::set_use_font_oversampling(bool p_oversampling) {
use_font_oversampling = p_oversampling;
_update_viewport_size();
}
+
bool Window::is_using_font_oversampling() const {
return use_font_oversampling;
}
DisplayServer::WindowID Window::get_window_id() const {
+ if (embedder) {
+ return parent->get_window_id();
+ }
return window_id;
}
@@ -861,8 +867,8 @@ Size2 Window::_get_contents_minimum_size() const {
return max;
}
-void Window::_update_child_controls() {
+void Window::_update_child_controls() {
if (!updating_child_controls) {
return;
}
@@ -871,20 +877,21 @@ void Window::_update_child_controls() {
updating_child_controls = false;
}
-void Window::child_controls_changed() {
+void Window::child_controls_changed() {
if (!is_inside_tree() || !visible || updating_child_controls) {
return;
}
updating_child_controls = true;
- call_deferred("_update_child_controls");
+ call_deferred(SNAME("_update_child_controls"));
}
-void Window::_window_input(const Ref<InputEvent> &p_ev) {
- if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_ev.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_ev)))
- return; //avoid joy input on editor
+bool Window::_can_consume_input_events() const {
+ return exclusive_child == nullptr;
+}
+void Window::_window_input(const Ref<InputEvent> &p_ev) {
if (EngineDebugger::is_active()) {
//quit from game window using F8
Ref<InputEventKey> k = p_ev;
@@ -894,26 +901,36 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
}
if (exclusive_child != nullptr) {
- exclusive_child->grab_focus();
-
- return; //has an exclusive child, can't get events until child is closed
+ /*
+ 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;
+ }
}
emit_signal(SceneStringNames::get_singleton()->window_input, p_ev);
- input(p_ev);
+
+ push_input(p_ev);
if (!is_input_handled()) {
- unhandled_input(p_ev);
+ push_unhandled_input(p_ev);
}
}
+
void Window::_window_input_text(const String &p_text) {
- input_text(p_text);
+ push_text_input(p_text);
}
+
void Window::_window_drop_files(const Vector<String> &p_files) {
- emit_signal("files_dropped", p_files, current_screen);
+ emit_signal(SNAME("files_dropped"), p_files, current_screen);
}
Viewport *Window::get_parent_viewport() const {
-
if (get_parent()) {
return get_parent()->get_viewport();
} else {
@@ -922,7 +939,6 @@ Viewport *Window::get_parent_viewport() const {
}
Window *Window::get_parent_visible_window() const {
-
Viewport *vp = get_parent_viewport();
Window *window = nullptr;
while (vp) {
@@ -940,7 +956,6 @@ Window *Window::get_parent_visible_window() const {
}
void Window::popup_on_parent(const Rect2i &p_parent_rect) {
-
ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
@@ -958,7 +973,6 @@ void Window::popup_on_parent(const Rect2i &p_parent_rect) {
}
void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio) {
-
ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
@@ -977,7 +991,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio
Rect2i popup_rect;
popup_rect.size = Vector2i(MIN(size_ratio.x, p_size.x), MIN(size_ratio.y, p_size.y));
- popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
+ popup_rect.position = parent_rect.position + (parent_rect.size - popup_rect.size) / 2;
popup(popup_rect);
}
@@ -1003,17 +1017,16 @@ void Window::popup_centered(const Size2i &p_minsize) {
} else {
popup_rect.size = p_minsize;
}
- popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
+ popup_rect.position = parent_rect.position + (parent_rect.size - popup_rect.size) / 2;
popup(popup_rect);
}
void Window::popup_centered_ratio(float p_ratio) {
-
ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
- Rect2i parent_rect;
+ Rect2 parent_rect;
if (is_embedded()) {
parent_rect = get_parent_viewport()->get_visible_rect();
@@ -1026,14 +1039,16 @@ void Window::popup_centered_ratio(float p_ratio) {
Rect2i popup_rect;
popup_rect.size = parent_rect.size * p_ratio;
- popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
+ popup_rect.position = parent_rect.position + (parent_rect.size - popup_rect.size) / 2;
popup(popup_rect);
}
void Window::popup(const Rect2i &p_screen_rect) {
+ emit_signal(SNAME("about_to_popup"));
- emit_signal("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);
@@ -1046,6 +1061,15 @@ void Window::popup(const Rect2i &p_screen_rect) {
set_size(adjust.size);
}
+ int scr = DisplayServer::get_singleton()->get_screen_count();
+ for (int i = 0; i < scr; i++) {
+ Rect2i r = DisplayServer::get_singleton()->screen_get_usable_rect(i);
+ if (r.has_point(position)) {
+ current_screen = i;
+ break;
+ }
+ }
+
set_transient(true);
set_visible(true);
_post_popup();
@@ -1074,7 +1098,6 @@ Rect2i Window::get_usable_parent_rect() const {
if (is_embedded()) {
parent = _get_embedder()->get_visible_rect();
} else {
-
const Window *w = is_visible() ? this : get_parent_visible_window();
//find a parent that can contain us
ERR_FAIL_COND_V(!w, Rect2());
@@ -1085,7 +1108,6 @@ Rect2i Window::get_usable_parent_rect() const {
}
void Window::add_child_notify(Node *p_child) {
-
Control *child_c = Object::cast_to<Control>(p_child);
if (child_c && child_c->data.theme.is_null() && (theme_owner || theme_owner_window)) {
@@ -1104,7 +1126,6 @@ void Window::add_child_notify(Node *p_child) {
}
void Window::remove_child_notify(Node *p_child) {
-
Control *child_c = Object::cast_to<Control>(p_child);
if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) {
@@ -1123,19 +1144,17 @@ void Window::remove_child_notify(Node *p_child) {
}
void Window::set_theme(const Ref<Theme> &p_theme) {
-
- if (theme == p_theme)
+ if (theme == p_theme) {
return;
+ }
theme = p_theme;
if (!p_theme.is_null()) {
-
theme_owner = nullptr;
theme_owner_window = this;
Control::_propagate_theme_changed(this, nullptr, this);
} else {
-
Control *parent_c = cast_to<Control>(get_parent());
if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window);
@@ -1149,58 +1168,102 @@ void Window::set_theme(const Ref<Theme> &p_theme) {
}
}
}
+
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);
}
-Ref<Shader> Window::get_theme_shader(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::get_shaders(theme_owner, theme_owner_window, p_name, type);
+
+StringName Window::get_theme_type_variation() const {
+ return theme_type_variation;
}
-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);
+
+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<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<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_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_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_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_shader(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::has_shaders(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_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_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(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_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 {
@@ -1239,8 +1302,91 @@ Rect2i Window::get_parent_rect() const {
}
}
-void Window::_bind_methods() {
+void Window::set_clamp_to_embedder(bool p_enable) {
+ clamp_to_embedder = p_enable;
+}
+
+bool Window::is_clamped_to_embedder() const {
+ return clamp_to_embedder;
+}
+
+void Window::set_layout_direction(Window::LayoutDirection p_direction) {
+ ERR_FAIL_INDEX((int)p_direction, 4);
+
+ layout_dir = p_direction;
+ propagate_notification(Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED);
+}
+
+Window::LayoutDirection Window::get_layout_direction() const {
+ return layout_dir;
+}
+
+bool Window::is_layout_rtl() const {
+ if (layout_dir == LAYOUT_DIRECTION_INHERITED) {
+ Window *parent = Object::cast_to<Window>(get_parent());
+ if (parent) {
+ return parent->is_layout_rtl();
+ } else {
+ 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(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 {
+ return (layout_dir == LAYOUT_DIRECTION_RTL);
+ }
+}
+
+void Window::set_auto_translate(bool p_enable) {
+ if (p_enable == auto_translate) {
+ return;
+ }
+
+ auto_translate = p_enable;
+
+ notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
+}
+bool Window::is_auto_translating() const {
+ return auto_translate;
+}
+
+void Window::_validate_property(PropertyInfo &property) const {
+ if (property.name == "theme_type_variation") {
+ List<StringName> names;
+
+ // Only the default theme and the project theme are used for the list of options.
+ // This is an imposed limitation to simplify the logic needed to leverage those options.
+ Theme::get_default()->get_type_variation_list(get_class_name(), &names);
+ if (Theme::get_project_default().is_valid()) {
+ Theme::get_project_default()->get_type_variation_list(get_class_name(), &names);
+ }
+ names.sort_custom<StringName::AlphCompare>();
+
+ Vector<StringName> unique_names;
+ String hint_string;
+ for (const StringName &E : names) {
+ // Skip duplicate values.
+ if (unique_names.has(E)) {
+ continue;
+ }
+
+ hint_string += String(E) + ",";
+ unique_names.append(E);
+ }
+
+ property.hint_string = hint_string;
+ }
+}
+
+void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title);
ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title);
@@ -1289,11 +1435,13 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_focus"), &Window::has_focus);
ClassDB::bind_method(D_METHOD("grab_focus"), &Window::grab_focus);
- ClassDB::bind_method(D_METHOD("set_ime_active"), &Window::set_ime_active);
- ClassDB::bind_method(D_METHOD("set_ime_position"), &Window::set_ime_position);
+ ClassDB::bind_method(D_METHOD("set_ime_active", "active"), &Window::set_ime_active);
+ ClassDB::bind_method(D_METHOD("set_ime_position", "position"), &Window::set_ime_position);
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);
@@ -1315,17 +1463,29 @@ 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_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("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_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("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", "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);
+ ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl);
+
+ ClassDB::bind_method(D_METHOD("set_auto_translate", "enable"), &Window::set_auto_translate);
+ ClassDB::bind_method(D_METHOD("is_auto_translating"), &Window::is_auto_translating);
ClassDB::bind_method(D_METHOD("popup", "rect"), &Window::popup, DEFVAL(Rect2i()));
ClassDB::bind_method(D_METHOD("popup_on_parent", "parent_rect"), &Window::popup_on_parent);
@@ -1336,8 +1496,9 @@ 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::STRING, "current_screen"), "set_current_screen", "get_current_screen");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen"), "set_current_screen", "get_current_screen");
+
ADD_GROUP("Flags", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls");
@@ -1348,15 +1509,22 @@ void Window::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "always_on_top"), "set_flag", "get_flag", FLAG_ALWAYS_ON_TOP);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_flag", "get_flag", FLAG_TRANSPARENT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS);
+
ADD_GROUP("Limits", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size"), "set_min_size", "get_min_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "max_size"), "set_max_size", "get_max_size");
+
ADD_GROUP("Content Scale", "content_scale_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "content_scale_size"), "set_content_scale_size", "get_content_scale_size");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_mode", PROPERTY_HINT_ENUM, "Disabled,Object,Pixels"), "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_GROUP("Auto Translate", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating");
ADD_SIGNAL(MethodInfo("window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files")));
@@ -1384,23 +1552,24 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
- BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_OBJECTS);
- BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_PIXELS);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_CANVAS_ITEMS);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_VIEWPORT);
BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_IGNORE);
BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP);
BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_WIDTH);
BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_HEIGHT);
BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_EXPAND);
+
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_INHERITED);
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE);
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LTR);
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_RTL);
}
Window::Window() {
- for (int i = 0; i < FLAG_MAX; i++) {
- flags[i] = false;
- }
- content_scale_mode = CONTENT_SCALE_MODE_DISABLED;
- content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE;
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
}
+
Window::~Window() {
}
diff --git a/scene/main/window.h b/scene/main/window.h
index adaa5ca3be..4f31d9cd1f 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,10 +32,12 @@
#define WINDOW_H
#include "scene/main/viewport.h"
-#include "scene/resources/theme.h"
-#include "servers/display_server.h"
class Control;
+class Font;
+class StyleBox;
+class Theme;
+
class Window : public Viewport {
GDCLASS(Window, Viewport)
public:
@@ -57,8 +59,8 @@ public:
enum ContentScaleMode {
CONTENT_SCALE_MODE_DISABLED,
- CONTENT_SCALE_MODE_OBJECTS,
- CONTENT_SCALE_MODE_PIXELS,
+ CONTENT_SCALE_MODE_CANVAS_ITEMS,
+ CONTENT_SCALE_MODE_VIEWPORT,
};
enum ContentScaleAspect {
@@ -69,6 +71,13 @@ public:
CONTENT_SCALE_ASPECT_EXPAND,
};
+ enum LayoutDirection {
+ LAYOUT_DIRECTION_INHERITED,
+ LAYOUT_DIRECTION_LOCALE,
+ LAYOUT_DIRECTION_LTR,
+ LAYOUT_DIRECTION_RTL
+ };
+
enum {
DEFAULT_WINDOW_SIZE = 100,
};
@@ -83,7 +92,7 @@ private:
mutable Size2i min_size;
mutable Size2i max_size;
mutable Mode mode = MODE_WINDOWED;
- mutable bool flags[FLAG_MAX];
+ mutable bool flags[FLAG_MAX] = {};
bool visible = true;
bool focused = false;
@@ -92,12 +101,17 @@ private:
bool exclusive = false;
bool wrap_controls = false;
bool updating_child_controls = false;
+ bool clamp_to_embedder = false;
+
+ LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED;
+
+ bool auto_translate = true;
void _update_child_controls();
Size2i content_scale_size;
- ContentScaleMode content_scale_mode;
- ContentScaleAspect content_scale_aspect;
+ ContentScaleMode content_scale_mode = CONTENT_SCALE_MODE_DISABLED;
+ ContentScaleAspect content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE;
void _make_window();
void _clear_window();
@@ -120,6 +134,7 @@ private:
Ref<Theme> theme;
Control *theme_owner = nullptr;
Window *theme_owner_window = nullptr;
+ StringName theme_type_variation;
Viewport *embedder = nullptr;
@@ -130,26 +145,26 @@ private:
void _window_drop_files(const Vector<String> &p_files);
void _rect_changed_callback(const Rect2i &p_callback);
void _event_callback(DisplayServer::WindowEvent p_event);
+ virtual bool _can_consume_input_events() const override;
protected:
Viewport *_get_embedder() const;
-
virtual Rect2i _popup_adjust_rect() const { return Rect2i(); }
virtual void _post_popup() {}
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);
- virtual void remove_child_notify(Node *p_child);
+ virtual void add_child_notify(Node *p_child) override;
+ virtual void remove_child_notify(Node *p_child) override;
public:
enum {
-
NOTIFICATION_VISIBILITY_CHANGED = 30,
NOTIFICATION_POST_POPUP = 31,
- NOTIFICATION_THEME_CHANGED = 32,
+ NOTIFICATION_THEME_CHANGED = 32
};
void set_title(const String &p_title);
@@ -195,6 +210,9 @@ public:
void set_exclusive(bool p_exclusive);
bool is_exclusive() const;
+ void set_clamp_to_embedder(bool p_enable);
+ bool is_clamped_to_embedder() const;
+
bool can_draw() const;
void set_ime_active(bool p_active);
@@ -229,29 +247,41 @@ 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();
bool has_focus() const;
+ void set_layout_direction(LayoutDirection p_direction);
+ LayoutDirection get_layout_direction() const;
+ bool is_layout_rtl() const;
+
+ void set_auto_translate(bool p_enable);
+ bool is_auto_translating() const;
+ _FORCE_INLINE_ String atr(const String p_string) const { return is_auto_translating() ? tr(p_string) : p_string; };
+
Rect2i get_usable_parent_rect() const;
- Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
- Ref<Shader> get_theme_shader(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;
- 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;
+ 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_type = StringName()) const;
- bool has_theme_shader(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_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;
+ 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;
+ virtual DisplayServer::WindowID get_window_id() const override;
Window();
~Window();
@@ -261,5 +291,6 @@ VARIANT_ENUM_CAST(Window::Mode);
VARIANT_ENUM_CAST(Window::Flags);
VARIANT_ENUM_CAST(Window::ContentScaleMode);
VARIANT_ENUM_CAST(Window::ContentScaleAspect);
+VARIANT_ENUM_CAST(Window::LayoutDirection);
#endif // WINDOW_H