summaryrefslogtreecommitdiff
path: root/scene/main
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main')
-rw-r--r--scene/main/canvas_layer.cpp51
-rw-r--r--scene/main/canvas_layer.h10
-rw-r--r--scene/main/http_request.cpp5
-rw-r--r--scene/main/node.cpp149
-rw-r--r--scene/main/node.h22
-rw-r--r--scene/main/scene_tree.cpp57
-rw-r--r--scene/main/scene_tree.h6
-rw-r--r--scene/main/viewport.cpp362
-rw-r--r--scene/main/viewport.h14
9 files changed, 471 insertions, 205 deletions
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 2b1991ebb0..8cab1b1280 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -153,6 +153,7 @@ void CanvasLayer::_notification(int p_what) {
VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ _update_follow_viewport();
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -160,6 +161,7 @@ void CanvasLayer::_notification(int p_what) {
vp->_canvas_layer_remove(this);
VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
+ _update_follow_viewport(false);
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
@@ -235,6 +237,41 @@ RID CanvasLayer::get_canvas() const {
return canvas;
}
+
+void CanvasLayer::set_follow_viewport(bool p_enable) {
+ if (follow_viewport == p_enable) {
+ return;
+ }
+
+ follow_viewport = p_enable;
+ _update_follow_viewport();
+}
+
+bool CanvasLayer::is_following_viewport() const {
+ return follow_viewport;
+}
+
+void CanvasLayer::set_follow_viewport_scale(float p_ratio) {
+ follow_viewport_scale = p_ratio;
+ _update_follow_viewport();
+}
+
+float CanvasLayer::get_follow_viewport_scale() const {
+ return follow_viewport_scale;
+}
+
+void CanvasLayer::_update_follow_viewport(bool p_force_exit) {
+
+ if (!is_inside_tree()) {
+ return;
+ }
+ if (p_force_exit || !follow_viewport) {
+ VS::get_singleton()->canvas_set_parent(canvas, RID(), 1.0);
+ } else {
+ VS::get_singleton()->canvas_set_parent(canvas, vp->get_world_2d()->get_canvas(), follow_viewport_scale);
+ }
+}
+
void CanvasLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer);
@@ -255,18 +292,30 @@ void CanvasLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &CanvasLayer::set_scale);
ClassDB::bind_method(D_METHOD("get_scale"), &CanvasLayer::get_scale);
+ ClassDB::bind_method(D_METHOD("set_follow_viewport", "enable"), &CanvasLayer::set_follow_viewport);
+ ClassDB::bind_method(D_METHOD("is_following_viewport"), &CanvasLayer::is_following_viewport);
+
+ ClassDB::bind_method(D_METHOD("set_follow_viewport_scale", "scale"), &CanvasLayer::set_follow_viewport_scale);
+ ClassDB::bind_method(D_METHOD("get_follow_viewport_scale"), &CanvasLayer::get_follow_viewport_scale);
+
ClassDB::bind_method(D_METHOD("set_custom_viewport", "viewport"), &CanvasLayer::set_custom_viewport);
ClassDB::bind_method(D_METHOD("get_custom_viewport"), &CanvasLayer::get_custom_viewport);
ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasLayer::get_canvas);
+ ADD_GROUP("Layer", "");
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::REAL, "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::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "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_GROUP("Follow Viewport", "follow_viewport");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enable"), "set_follow_viewport", "is_following_viewport");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "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() {
@@ -280,6 +329,8 @@ CanvasLayer::CanvasLayer() {
custom_viewport = NULL;
custom_viewport_id = 0;
sort_index = 0;
+ follow_viewport = false;
+ follow_viewport_scale = 1.0;
}
CanvasLayer::~CanvasLayer() {
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index 5d67245102..fa2558556c 100644
--- a/scene/main/canvas_layer.h
+++ b/scene/main/canvas_layer.h
@@ -55,8 +55,12 @@ class CanvasLayer : public Node {
int sort_index;
+ bool follow_viewport;
+ float follow_viewport_scale;
+
void _update_xform();
void _update_locrotscale();
+ void _update_follow_viewport(bool p_force_exit = false);
protected:
void _notification(int p_what);
@@ -91,6 +95,12 @@ public:
void reset_sort_index();
int get_sort_index();
+ void set_follow_viewport(bool p_enable);
+ bool is_following_viewport() const;
+
+ void set_follow_viewport_scale(float p_ratio);
+ float get_follow_viewport_scale() const;
+
RID get_canvas() const;
CanvasLayer();
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 8e96873672..e65314644e 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -220,13 +220,12 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
Error err;
if (new_request.begins_with("http")) {
// New url, request all again
- err = _parse_url(new_request);
+ _parse_url(new_request);
} else {
request_string = new_request;
}
err = _request();
-
if (err == OK) {
request_sent = false;
got_response = false;
@@ -287,7 +286,7 @@ bool HTTPRequest::_update_connection() {
call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, PoolByteArray());
return true;
}
- if (got_response && body_len < 0) {
+ if (body_len < 0) {
// Chunked transfer is done
call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
return true;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 89b740e9a9..2f23c11748 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -39,8 +39,14 @@
#include "scene/scene_string_names.h"
#include "viewport.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif
+
VARIANT_ENUM_CAST(Node::PauseMode);
+int Node::orphan_node_count = 0;
+
void Node::_notification(int p_notification) {
switch (p_notification) {
@@ -84,11 +90,14 @@ void Node::_notification(int p_notification) {
add_to_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id()));
get_tree()->node_count++;
+ orphan_node_count--;
} break;
case NOTIFICATION_EXIT_TREE: {
get_tree()->node_count--;
+ orphan_node_count++;
+
if (data.input)
remove_from_group("_vp_input" + itos(get_viewport()->get_instance_id()));
if (data.unhandled_input)
@@ -940,6 +949,7 @@ void Node::set_name(const String &p_name) {
if (is_inside_tree()) {
emit_signal("renamed");
+ get_tree()->node_renamed(this);
get_tree()->tree_changed();
}
}
@@ -959,7 +969,9 @@ void Node::set_human_readable_collision_renaming(bool p_enabled) {
#ifdef TOOLS_ENABLED
String Node::validate_child_name(Node *p_child) {
- return _generate_serial_child_name(p_child);
+ StringName name = p_child->data.name;
+ _generate_serial_child_name(p_child, name);
+ return name;
}
#endif
@@ -972,7 +984,9 @@ void Node::_validate_child_name(Node *p_child, bool 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
- p_child->data.name = _generate_serial_child_name(p_child);
+ StringName name = p_child->data.name;
+ _generate_serial_child_name(p_child, name);
+ p_child->data.name = name;
} else {
@@ -1034,68 +1048,92 @@ String increase_numeric_string(const String &s) {
return res;
}
-String Node::_generate_serial_child_name(Node *p_child) {
-
- String name = p_child->data.name;
+void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const {
- if (name == "") {
+ if (name == StringName()) {
+ //no name and a new nade 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()) {
case NAME_CASING_PASCAL_CASE:
break;
- case NAME_CASING_CAMEL_CASE:
- name[0] = name.to_lower()[0];
- break;
+ case NAME_CASING_CAMEL_CASE: {
+ String n = name;
+ n[0] = n.to_lower()[0];
+ name = n;
+ } break;
case NAME_CASING_SNAKE_CASE:
- name = name.camelcase_to_underscore(true);
+ name = String(name).camelcase_to_underscore(true);
break;
}
}
+ //quickly test if proposed name exists
+ int cc = data.children.size(); //children count
+ 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
+ continue;
+ }
+ if (children_ptr[i]->data.name == name) {
+ exists = true;
+ }
+ }
+
+ if (!exists) {
+ return; //if it does not exist, it does not need validation
+ }
+ }
+
// Extract trailing number
+ String name_string = name;
String nums;
- for (int i = name.length() - 1; i >= 0; i--) {
- CharType n = name[i];
+ for (int i = name_string.length() - 1; i >= 0; i--) {
+ CharType n = name_string[i];
if (n >= '0' && n <= '9') {
- nums = String::chr(name[i]) + nums;
+ nums = String::chr(name_string[i]) + nums;
} else {
break;
}
}
String nnsep = _get_name_num_separator();
- int name_last_index = name.length() - nnsep.length() - nums.length();
+ int name_last_index = name_string.length() - nnsep.length() - nums.length();
// Assign the base name + separator to name if we have numbers preceded by a separator
- if (nums.length() > 0 && name.substr(name_last_index, nnsep.length()) == nnsep) {
- name = name.substr(0, name_last_index + nnsep.length()).strip_edges();
+ if (nums.length() > 0 && name_string.substr(name_last_index, nnsep.length()) == nnsep) {
+ name_string = name_string.substr(0, name_last_index + nnsep.length());
} else {
nums = "";
}
- Vector<String> children_names;
+ for (;;) {
+ StringName attempt = name_string + nums;
+ bool exists = false;
- for (int i = 0; i < data.children.size(); i++) {
- String child_name = data.children[i]->data.name;
- if (data.children[i] == p_child)
- continue;
- if (child_name.begins_with(name)) {
- children_names.push_back(child_name);
+ for (int i = 0; i < cc; i++) {
+ if (children_ptr[i] == p_child) {
+ continue;
+ }
+ if (children_ptr[i]->data.name == attempt) {
+ exists = true;
+ }
}
- }
- for (;;) {
- String attempt = name + nums;
-
- if (children_names.find(attempt) == -1) {
- return attempt;
+ if (!exists) {
+ name = attempt;
+ return;
} else {
if (nums.length() == 0) {
// Name was undecorated so skip to 2 for a more natural result
nums = "2";
- name += nnsep; // Add separator because nums.length() > 0 was false
+ name_string += nnsep; // Add separator because nums.length() > 0 was false
} else {
nums = increase_numeric_string(nums);
}
@@ -1283,7 +1321,11 @@ Node *Node::_get_child_by_name(const StringName &p_name) const {
return NULL;
}
-Node *Node::_get_node(const NodePath &p_path) const {
+Node *Node::get_node_or_null(const NodePath &p_path) const {
+
+ if (p_path.is_empty()) {
+ return NULL;
+ }
if (!data.inside_tree && p_path.is_absolute()) {
ERR_EXPLAIN("Can't use get_node() with absolute paths from outside the active scene tree.");
@@ -1348,7 +1390,7 @@ Node *Node::_get_node(const NodePath &p_path) const {
Node *Node::get_node(const NodePath &p_path) const {
- Node *node = _get_node(p_path);
+ Node *node = get_node_or_null(p_path);
if (!node) {
ERR_EXPLAIN("Node not found: " + p_path);
ERR_FAIL_COND_V(!node, NULL);
@@ -1358,7 +1400,7 @@ Node *Node::get_node(const NodePath &p_path) const {
bool Node::has_node(const NodePath &p_path) const {
- return _get_node(p_path) != NULL;
+ return get_node_or_null(p_path) != NULL;
}
Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) const {
@@ -2035,7 +2077,9 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
}
}
- node->set_name(get_name());
+ if (get_name() != String()) {
+ node->set_name(get_name());
+ }
#ifdef TOOLS_ENABLED
if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap)
@@ -2389,7 +2433,7 @@ void Node::_replace_connections_target(Node *p_new_target) {
if (c.flags & CONNECT_PERSIST) {
c.source->disconnect(c.signal, this, c.method);
- bool valid = p_new_target->has_method(c.method) || p_new_target->get_script().is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.method);
+ bool valid = p_new_target->has_method(c.method) || Ref<Script>(p_new_target->get_script()).is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.method);
ERR_EXPLAIN("Attempt to connect signal \'" + c.source->get_class() + "." + c.signal + "\' to nonexistent method \'" + c.target->get_class() + "." + c.method + "\'");
ERR_CONTINUE(!valid);
c.source->connect(c.signal, p_new_target, c.method, c.binds, c.flags);
@@ -2600,10 +2644,16 @@ 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) ? "'" : "\"";
+#else
+ const String quote_style = "\"";
+#endif
+
if (p_node != p_base && !p_node->get_owner())
return;
String n = p_base->get_path_to(p_node);
- r_options->push_back("\"" + n + "\"");
+ r_options->push_back(quote_style + n + 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);
}
@@ -2681,6 +2731,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_child", "idx"), &Node::get_child);
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);
ClassDB::bind_method(D_METHOD("get_parent"), &Node::get_parent);
ClassDB::bind_method(D_METHOD("find_node", "mask", "recursive", "owned"), &Node::find_node, DEFVAL(true), DEFVAL(true));
ClassDB::bind_method(D_METHOD("find_parent", "mask"), &Node::find_parent);
@@ -2726,6 +2777,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process);
ClassDB::bind_method(D_METHOD("print_stray_nodes"), &Node::_print_stray_nodes);
ClassDB::bind_method(D_METHOD("get_position_in_parent"), &Node::get_position_in_parent);
+
ClassDB::bind_method(D_METHOD("set_display_folded", "fold"), &Node::set_display_folded);
ClassDB::bind_method(D_METHOD("is_displayed_folded"), &Node::is_displayed_folded);
@@ -2801,10 +2853,22 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_DRAG_BEGIN);
BIND_CONSTANT(NOTIFICATION_DRAG_END);
BIND_CONSTANT(NOTIFICATION_PATH_CHANGED);
- BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED);
BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS);
BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
+ 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_QUIT_REQUEST);
+ BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST);
+ BIND_CONSTANT(NOTIFICATION_WM_UNFOCUS_REQUEST);
+ BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
+ BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED);
+ BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
+ BIND_CONSTANT(NOTIFICATION_CRASH);
+ BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE);
+
BIND_ENUM_CONSTANT(PAUSE_MODE_INHERIT);
BIND_ENUM_CONSTANT(PAUSE_MODE_STOP);
BIND_ENUM_CONSTANT(PAUSE_MODE_PROCESS);
@@ -2826,7 +2890,12 @@ void Node::_bind_methods() {
//ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), "set_process_unhandled_input","is_processing_unhandled_input" ) ;
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::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_display_folded", "is_displayed_folded");
+
+#ifdef ENABLE_DEPRECATED
+ //no longer exists, but remains for compatibility (keep previous scenes folded
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", 0), "set_display_folded", "is_displayed_folded");
+#endif
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "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");
@@ -2887,6 +2956,8 @@ Node::Node() {
data.use_placeholder = false;
data.display_folded = false;
data.ready_first = true;
+
+ orphan_node_count++;
}
Node::~Node() {
@@ -2897,6 +2968,8 @@ Node::~Node() {
ERR_FAIL_COND(data.parent);
ERR_FAIL_COND(data.children.size());
+
+ orphan_node_count--;
}
////////////////////////////////
diff --git a/scene/main/node.h b/scene/main/node.h
index 9abe07ac88..9b9ca06455 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -75,6 +75,8 @@ public:
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; }
};
+ static int orphan_node_count;
+
private:
struct GroupData {
@@ -153,13 +155,12 @@ private:
void _print_tree_pretty(const String prefix, const bool last);
void _print_tree(const Node *p_node);
- Node *_get_node(const NodePath &p_path) const;
Node *_get_child_by_name(const StringName &p_name) const;
void _replace_connections_target(Node *p_new_target);
void _validate_child_name(Node *p_child, bool p_force_human_readable = false);
- String _generate_serial_child_name(Node *p_child);
+ void _generate_serial_child_name(const Node *p_child, StringName &name) const;
void _propagate_reverse_notification(int p_notification);
void _propagate_deferred_notification(int p_notification, bool p_reverse);
@@ -217,6 +218,7 @@ protected:
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,
@@ -232,10 +234,23 @@ public:
NOTIFICATION_DRAG_BEGIN = 21,
NOTIFICATION_DRAG_END = 22,
NOTIFICATION_PATH_CHANGED = 23,
- NOTIFICATION_TRANSLATION_CHANGED = 24,
+ //NOTIFICATION_TRANSLATION_CHANGED = 24, moved below
NOTIFICATION_INTERNAL_PROCESS = 25,
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
NOTIFICATION_POST_ENTER_TREE = 27,
+ //keep these linked to node
+ NOTIFICATION_WM_MOUSE_ENTER = MainLoop::NOTIFICATION_WM_MOUSE_ENTER,
+ NOTIFICATION_WM_MOUSE_EXIT = MainLoop::NOTIFICATION_WM_MOUSE_EXIT,
+ NOTIFICATION_WM_FOCUS_IN = MainLoop::NOTIFICATION_WM_FOCUS_IN,
+ NOTIFICATION_WM_FOCUS_OUT = MainLoop::NOTIFICATION_WM_FOCUS_OUT,
+ NOTIFICATION_WM_QUIT_REQUEST = MainLoop::NOTIFICATION_WM_QUIT_REQUEST,
+ NOTIFICATION_WM_GO_BACK_REQUEST = MainLoop::NOTIFICATION_WM_GO_BACK_REQUEST,
+ NOTIFICATION_WM_UNFOCUS_REQUEST = MainLoop::NOTIFICATION_WM_UNFOCUS_REQUEST,
+ NOTIFICATION_OS_MEMORY_WARNING = MainLoop::NOTIFICATION_OS_MEMORY_WARNING,
+ NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED,
+ NOTIFICATION_WM_ABOUT = MainLoop::NOTIFICATION_WM_ABOUT,
+ NOTIFICATION_CRASH = MainLoop::NOTIFICATION_CRASH,
+ NOTIFICATION_OS_IME_UPDATE = MainLoop::NOTIFICATION_OS_IME_UPDATE
};
@@ -252,6 +267,7 @@ public:
Node *get_child(int p_index) 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;
Node *find_node(const String &p_mask, bool p_recursive = true, bool p_owned = true) const;
bool has_node_and_resource(const NodePath &p_path) const;
Node *get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property = true) const;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 5acb157279..65cda73a23 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -105,6 +105,11 @@ void SceneTree::node_removed(Node *p_node) {
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);
@@ -369,8 +374,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
}
void SceneTree::call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) {
-
- call_group_flags(0, p_group, VARIANT_ARG_PASS);
+ call_group_flags(0, p_group, p_function, VARIANT_ARG_PASS);
}
void SceneTree::notify_group(const StringName &p_group, int p_notification) {
@@ -484,6 +488,14 @@ bool SceneTree::iteration(float p_time) {
return _quit;
}
+void SceneTree::_update_font_oversampling(float p_ratio) {
+
+ if (use_font_oversampling) {
+ DynamicFontAtSize::font_oversampling = p_ratio;
+ DynamicFont::update_oversampling();
+ }
+}
+
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()));
@@ -515,12 +527,6 @@ bool SceneTree::idle(float p_time) {
last_screen_size = win_size;
_update_root_rect();
-
- if (use_font_oversampling) {
- DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width;
- DynamicFont::update_oversampling();
- }
-
emit_signal("screen_resized");
}
@@ -656,13 +662,15 @@ void SceneTree::_notification(int p_notification) {
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
if (!Engine::get_singleton()->is_editor_hint()) {
- get_root()->propagate_notification(Node::NOTIFICATION_TRANSLATION_CHANGED);
+ get_root()->propagate_notification(p_notification);
}
} break;
case NOTIFICATION_WM_UNFOCUS_REQUEST: {
notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST);
+ get_root()->propagate_notification(p_notification);
+
} break;
case NOTIFICATION_WM_ABOUT: {
@@ -1133,10 +1141,12 @@ void SceneTree::_update_root_rect() {
if (stretch_mode == STRETCH_MODE_DISABLED) {
+ _update_font_oversampling(1.0);
root->set_size((last_screen_size / stretch_shrink).floor());
root->set_attach_to_screen_rect(Rect2(Point2(), last_screen_size));
root->set_size_override_stretch(false);
root->set_size_override(false, Size2());
+ root->update_canvas_items();
return; //user will take care
}
@@ -1150,7 +1160,11 @@ void SceneTree::_update_root_rect() {
float viewport_aspect = desired_res.aspect();
float video_mode_aspect = video_mode.aspect();
- if (stretch_aspect == STRETCH_ASPECT_IGNORE || ABS(viewport_aspect - video_mode_aspect) < CMP_EPSILON) {
+ if (use_font_oversampling && stretch_aspect == STRETCH_ASPECT_IGNORE) {
+ WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'.");
+ }
+
+ if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) {
//same aspect or ignore aspect
viewport_size = desired_res;
screen_size = video_mode;
@@ -1208,21 +1222,30 @@ void SceneTree::_update_root_rect() {
switch (stretch_mode) {
case STRETCH_MODE_DISABLED: {
// Already handled above
+ _update_font_oversampling(1.0);
} break;
case STRETCH_MODE_2D: {
+ _update_font_oversampling(screen_size.x / viewport_size.x); //screen / viewport radio drives oversampling
root->set_size((screen_size / stretch_shrink).floor());
root->set_attach_to_screen_rect(Rect2(margin, screen_size));
root->set_size_override_stretch(true);
root->set_size_override(true, (viewport_size / stretch_shrink).floor());
+ root->update_canvas_items(); //force them to update just in case
} break;
case STRETCH_MODE_VIEWPORT: {
+ _update_font_oversampling(1.0);
root->set_size((viewport_size / stretch_shrink).floor());
root->set_attach_to_screen_rect(Rect2(margin, screen_size));
root->set_size_override_stretch(false);
root->set_size_override(false, Size2());
+ root->update_canvas_items(); //force them to update just in case
+
+ if (use_font_oversampling) {
+ WARN_PRINT("Font oversampling does not work in 'Viewport' stretch mode, only '2D'.")
+ }
} break;
}
@@ -1877,6 +1900,7 @@ void SceneTree::_bind_methods() {
ADD_SIGNAL(MethodInfo("tree_changed"));
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("screen_resized"));
ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
@@ -1925,12 +1949,11 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) {
void SceneTree::set_use_font_oversampling(bool p_oversampling) {
+ if (use_font_oversampling == p_oversampling)
+ return;
+
use_font_oversampling = p_oversampling;
- if (use_font_oversampling) {
- DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width;
- } else {
- DynamicFontAtSize::font_oversampling = 1.0;
- }
+ _update_root_rect();
}
bool SceneTree::is_using_font_oversampling() const {
@@ -1944,6 +1967,7 @@ SceneTree::SceneTree() {
accept_quit = true;
quit_on_go_back = true;
initialized = false;
+ use_font_oversampling = false;
#ifdef DEBUG_ENABLED
debug_collisions_hint = false;
debug_navigation_hint = false;
@@ -1965,6 +1989,7 @@ SceneTree::SceneTree() {
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;
@@ -2079,8 +2104,6 @@ SceneTree::SceneTree() {
live_edit_root = NodePath("/root");
#endif
-
- use_font_oversampling = false;
}
SceneTree::~SceneTree() {
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index d6ab8c37b2..0bcb724929 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -43,7 +43,6 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
-class SceneTree;
class PackedScene;
class Node;
class Viewport;
@@ -127,6 +126,7 @@ private:
StringName tree_changed_name;
StringName node_added_name;
StringName node_removed_name;
+ StringName node_renamed_name;
bool use_font_oversampling;
int64_t current_frame;
@@ -153,6 +153,7 @@ private:
Size2i stretch_min;
real_t stretch_shrink;
+ void _update_font_oversampling(float p_ratio);
void _update_root_rect();
List<ObjectID> delete_queue;
@@ -201,6 +202,7 @@ private:
void tree_changed();
void node_added(Node *p_node);
void node_removed(Node *p_node);
+ void node_renamed(Node *p_node);
Group *add_to_group(const StringName &p_group, Node *p_node);
void remove_from_group(const StringName &p_group, Node *p_node);
@@ -287,7 +289,7 @@ protected:
public:
enum {
- NOTIFICATION_TRANSFORM_CHANGED = 29
+ NOTIFICATION_TRANSFORM_CHANGED = 2000
};
enum GroupCallFlags {
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 52738a1114..c02873cdeb 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -37,8 +37,8 @@
#include "scene/3d/camera.h"
#include "scene/3d/collision_object.h"
#include "scene/3d/listener.h"
-#include "scene/3d/scenario_fx.h"
#include "scene/3d/spatial.h"
+#include "scene/3d/world_environment.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
#include "scene/gui/menu_button.h"
@@ -148,7 +148,7 @@ 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);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport"), "set_viewport_path_in_scene", "get_viewport_path_in_scene");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT), "set_viewport_path_in_scene", "get_viewport_path_in_scene");
}
ViewportTexture::ViewportTexture() {
@@ -232,16 +232,16 @@ void Viewport::update_worlds() {
find_world()->_update(get_tree()->get_frame());
}
-void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape, bool p_discard_empty_motion) {
+void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *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();
- if (p_discard_empty_motion) {
- //avoid sending the event unnecesarily if nothing really changed in the context
+ //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() && object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) {
+ if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
return; //discarded
}
}
@@ -251,31 +251,6 @@ void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *
physics_last_id = id;
}
-void Viewport::_test_new_mouseover(ObjectID new_collider) {
-#ifndef _3D_DISABLED
- if (new_collider != physics_object_over) {
-
- if (physics_object_over) {
-
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
- if (co) {
- co->_mouse_exit();
- }
- }
-
- if (new_collider) {
-
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider));
- if (co) {
- co->_mouse_enter();
- }
- }
-
- physics_object_over = new_collider;
- }
-#endif
-}
-
void Viewport::_notification(int p_what) {
switch (p_what) {
@@ -416,28 +391,30 @@ void Viewport::_notification(int p_what) {
if (physics_object_picking && (to_screen_rect == Rect2() || Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED)) {
+#ifndef _3D_DISABLED
Vector2 last_pos(1e20, 1e20);
CollisionObject *last_object = NULL;
ObjectID last_id = 0;
+#endif
PhysicsDirectSpaceState::RayResult result;
Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
- bool discard_empty_motion = false;
-
- { // if no motion event exists, create a new 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 unnecesary motion events every frame
- bool has_mouse_motion = false;
+ 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<InputEventMouseMotion> mm = E->get();
- if (mm.is_valid()) {
- has_mouse_motion = true;
+ Ref<InputEventMouse> m = E->get();
+ if (m.is_valid()) {
+ has_mouse_event = true;
break;
}
}
- if (!has_mouse_motion && physics_has_last_mousepos) {
+ 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);
@@ -446,25 +423,24 @@ void Viewport::_notification(int p_what) {
mm->set_metakey(physics_last_mouse_state.meta);
mm->set_button_mask(physics_last_mouse_state.mouse_mask);
physics_picking_events.push_back(mm);
- discard_empty_motion = true;
}
}
- bool motion_tested = false;
-
while (physics_picking_events.size()) {
Ref<InputEvent> ev = physics_picking_events.front()->get();
physics_picking_events.pop_front();
Vector2 pos;
+ bool is_mouse = false;
Ref<InputEventMouseMotion> mm = ev;
if (mm.is_valid()) {
pos = mm->get_position();
- motion_tested = true;
+ is_mouse = true;
+
physics_has_last_mousepos = true;
physics_last_mousepos = pos;
physics_last_mouse_state.alt = mm->get_alt();
@@ -477,7 +453,12 @@ void Viewport::_notification(int p_what) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid()) {
+
pos = mb->get_position();
+ is_mouse = true;
+
+ 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();
@@ -487,6 +468,11 @@ void Viewport::_notification(int p_what) {
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));
+
+ // 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;
+ }
}
}
@@ -539,40 +525,51 @@ void Viewport::_notification(int p_what) {
if (res[i].collider_id && res[i].collider) {
CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
if (co) {
-
- Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.find(res[i].collider_id);
- if (!E) {
- E = physics_2d_mouseover.insert(res[i].collider_id, frame);
- co->_mouse_enter();
- } else {
- E->get() = frame;
+ bool send_event = true;
+ if (is_mouse) {
+ Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id);
+
+ if (!F) {
+ 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;
+ }
+ }
}
- co->_input_event(this, ev, res[i].shape);
+ if (send_event) {
+ co->_input_event(this, ev, res[i].shape);
+ }
}
}
}
}
- List<Map<ObjectID, uint64_t>::Element *> to_erase;
+ if (is_mouse) {
+ List<Map<ObjectID, uint64_t>::Element *> to_erase;
- for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) {
- if (E->get() != frame) {
- Object *o = ObjectDB::get_instance(E->key());
- if (o) {
+ for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) {
+ if (E->get() != frame) {
+ Object *o = ObjectDB::get_instance(E->key());
+ if (o) {
- CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
- if (co) {
- co->_mouse_exit();
+ CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
+ if (co) {
+ co->_mouse_exit();
+ }
}
+ to_erase.push_back(E);
}
- to_erase.push_back(E);
}
- }
- while (to_erase.size()) {
- physics_2d_mouseover.erase(to_erase.front()->get());
- to_erase.pop_front();
+ while (to_erase.size()) {
+ physics_2d_mouseover.erase(to_erase.front()->get());
+ to_erase.pop_front();
+ }
}
}
@@ -583,7 +580,7 @@ void Viewport::_notification(int p_what) {
CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_capture));
if (co) {
- _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0, discard_empty_motion);
+ _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 = 0;
@@ -601,7 +598,7 @@ void Viewport::_notification(int p_what) {
if (last_id) {
if (ObjectDB::get_instance(last_id) && last_object) {
//good, exists
- _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape, discard_empty_motion);
+ _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;
}
@@ -624,7 +621,7 @@ void Viewport::_notification(int p_what) {
CollisionObject *co = Object::cast_to<CollisionObject>(result.collider);
if (co) {
- _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape, discard_empty_motion);
+ _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;
@@ -634,42 +631,41 @@ void Viewport::_notification(int p_what) {
}
}
- if (mm.is_valid()) {
- _test_new_mouseover(new_collider);
- }
- }
+ if (is_mouse && new_collider != physics_object_over) {
- last_pos = pos;
- }
- }
- }
+ if (physics_object_over) {
- if (!motion_tested && camera && physics_has_last_mousepos) {
+ CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
+ if (co) {
+ co->_mouse_exit();
+ }
+ }
- //test anyway for mouseenter/exit because objects might move
- Vector3 from = camera->project_ray_origin(physics_last_mousepos);
- Vector3 dir = camera->project_ray_normal(physics_last_mousepos);
+ if (new_collider) {
- PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
- if (space) {
+ CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider));
+ if (co) {
+ co->_mouse_enter();
+ }
+ }
- bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
- ObjectID new_collider = 0;
- if (col) {
- CollisionObject *co = Object::cast_to<CollisionObject>(result.collider);
- if (co) {
- new_collider = result.collider_id;
+ physics_object_over = new_collider;
+ }
}
- }
- _test_new_mouseover(new_collider);
+ last_pos = pos;
+ }
}
#endif
}
}
} break;
+ case SceneTree::NOTIFICATION_WM_MOUSE_EXIT:
case SceneTree::NOTIFICATION_WM_FOCUS_OUT: {
+
+ _drop_physics_mouseover();
+
if (gui.mouse_focus) {
//if mouse is being pressed, send a release event
_drop_mouse_focus();
@@ -693,6 +689,13 @@ bool Viewport::use_arvr() {
return arvr;
}
+void Viewport::update_canvas_items() {
+ if (!is_inside_tree())
+ return;
+
+ _update_canvas_items(this);
+}
+
void Viewport::set_size(const Size2 &p_size) {
if (size == p_size.floor())
@@ -883,7 +886,7 @@ void Viewport::_camera_set(Camera *p_camera) {
if (camera == p_camera)
return;
- if (camera && find_world().is_valid()) {
+ if (camera) {
camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
}
camera = p_camera;
@@ -892,7 +895,7 @@ void Viewport::_camera_set(Camera *p_camera) {
else
VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
- if (camera && find_world().is_valid()) {
+ if (camera) {
camera->notification(Camera::NOTIFICATION_BECAME_CURRENT);
}
@@ -911,9 +914,7 @@ void Viewport::_camera_remove(Camera *p_camera) {
cameras.erase(p_camera);
if (camera == p_camera) {
- if (camera && find_world().is_valid()) {
- camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
- }
+ camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
camera = NULL;
}
}
@@ -1010,7 +1011,7 @@ void Viewport::_propagate_enter_world(Node *p_node) {
Viewport *v = Object::cast_to<Viewport>(p_node);
if (v) {
- if (v->world.is_valid())
+ if (v->world.is_valid() || v->own_world.is_valid())
return;
}
}
@@ -1047,7 +1048,7 @@ void Viewport::_propagate_exit_world(Node *p_node) {
Viewport *v = Object::cast_to<Viewport>(p_node);
if (v) {
- if (v->world.is_valid())
+ if (v->world.is_valid() || v->own_world.is_valid())
return;
}
}
@@ -1067,23 +1068,11 @@ void Viewport::set_world(const Ref<World> &p_world) {
if (is_inside_tree())
_propagate_exit_world(this);
-#ifndef _3D_DISABLED
- if (find_world().is_valid() && camera)
- camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
-#endif
-
world = p_world;
if (is_inside_tree())
_propagate_enter_world(this);
-#ifndef _3D_DISABLED
- if (find_world().is_valid() && camera)
- camera->notification(Camera::NOTIFICATION_BECAME_CURRENT);
-#endif
-
- //propagate exit
-
if (is_inside_tree()) {
VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
}
@@ -1128,6 +1117,26 @@ 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)
+ return;
+
+ CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
+ if (ci) {
+ ci->update();
+ }
+ }
+
+ int cc = p_node->get_child_count();
+
+ for (int i = 0; i < cc; i++) {
+ _update_canvas_items(p_node->get_child(i));
+ }
+}
+
void Viewport::set_size_override(bool p_enable, const Size2 &p_size, const Vector2 &p_margin) {
if (size_override == p_enable && p_size == size_override_size)
@@ -1459,7 +1468,8 @@ void Viewport::_gui_show_tooltip() {
gui.tooltip_popup->set_as_toplevel(true);
//gui.tooltip_popup->hide();
- Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_popup->get_minimum_size());
+ Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
+ Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size());
Rect2 vr = gui.tooltip_popup->get_viewport_rect();
if (r.size.x + r.position.x > vr.size.x)
r.position.x = vr.size.x - r.size.x;
@@ -1533,6 +1543,35 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
//_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())
+ break;
+
+ if (!control->is_inside_tree() || control->is_set_as_toplevel())
+ break;
+ if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
+ break;
+ }
+
+ if (ci->is_set_as_toplevel())
+ break;
+
+ ci = ci->get_parent_item();
+ }
+
+ //_unblock();
+}
Control *Viewport::_gui_find_control(const Point2 &p_global) {
_gui_prepare_subwindows();
@@ -1691,8 +1730,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
while (!gui.modal_stack.empty()) {
Control *top = gui.modal_stack.back()->get();
- Vector2 pos = top->get_global_transform_with_canvas().affine_inverse().xform(mpos);
- if (!top->has_point(pos)) {
+ Vector2 pos2 = top->get_global_transform_with_canvas().affine_inverse().xform(mpos);
+ if (!top->has_point(pos2)) {
if (top->data.modal_exclusive || top->data.modal_frame == Engine::get_singleton()->get_frames_drawn()) {
//cancel event, sorry, modal exclusive EATS UP ALL
@@ -1727,13 +1766,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
*/
gui.mouse_focus = _gui_find_control(pos);
- gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1);
gui.last_mouse_focus = gui.mouse_focus;
if (!gui.mouse_focus) {
+ gui.mouse_focus_mask = 0;
return;
}
+ gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1);
+
if (mb->get_button_index() == BUTTON_LEFT) {
gui.drag_accum = Vector2();
gui.drag_attempted = false;
@@ -1975,13 +2016,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (over != gui.mouse_over) {
- if (gui.mouse_over)
- gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT);
+ if (gui.mouse_over) {
+ _gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT);
+ }
_gui_cancel_tooltip();
- if (over)
- over->notification(Control::NOTIFICATION_MOUSE_ENTER);
+ if (over) {
+ _gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER);
+ }
}
gui.mouse_over = over;
@@ -2245,32 +2288,32 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (from && p_event->is_pressed()) {
Control *next = NULL;
- if (p_event->is_action("ui_focus_next")) {
+ if (p_event->is_action_pressed("ui_focus_next")) {
next = from->find_next_valid_focus();
}
- if (p_event->is_action("ui_focus_prev")) {
+ if (p_event->is_action_pressed("ui_focus_prev")) {
next = from->find_prev_valid_focus();
}
- if (!mods && p_event->is_action("ui_up")) {
+ if (!mods && p_event->is_action_pressed("ui_up")) {
next = from->_get_focus_neighbour(MARGIN_TOP);
}
- if (!mods && p_event->is_action("ui_left")) {
+ if (!mods && p_event->is_action_pressed("ui_left")) {
next = from->_get_focus_neighbour(MARGIN_LEFT);
}
- if (!mods && p_event->is_action("ui_right")) {
+ if (!mods && p_event->is_action_pressed("ui_right")) {
next = from->_get_focus_neighbour(MARGIN_RIGHT);
}
- if (!mods && p_event->is_action("ui_down")) {
+ if (!mods && p_event->is_action_pressed("ui_down")) {
next = from->_get_focus_neighbour(MARGIN_BOTTOM);
}
@@ -2425,11 +2468,7 @@ void Viewport::_gui_hid_control(Control *p_control) {
if (gui.mouse_over == p_control)
gui.mouse_over = NULL;
if (gui.tooltip == p_control)
- gui.tooltip = NULL;
- if (gui.tooltip == p_control) {
- gui.tooltip = NULL;
_gui_cancel_tooltip();
- }
}
void Viewport::_gui_remove_control(Control *p_control) {
@@ -2438,6 +2477,9 @@ void Viewport::_gui_remove_control(Control *p_control) {
gui.mouse_focus = NULL;
gui.mouse_focus_mask = 0;
}
+ if (gui.last_mouse_focus == p_control) {
+ gui.last_mouse_focus = NULL;
+ }
if (gui.key_focus == p_control)
gui.key_focus = NULL;
if (gui.mouse_over == p_control)
@@ -2507,6 +2549,31 @@ void Viewport::_drop_mouse_focus() {
}
}
+void Viewport::_drop_physics_mouseover() {
+
+ 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());
+ }
+
+#ifndef _3D_DISABLED
+ if (physics_object_over) {
+ CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
+ if (co) {
+ co->_mouse_exit();
+ }
+ }
+
+ physics_object_over = physics_object_capture = 0;
+#endif
+}
+
List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
gui.modal_stack.push_back(p_control);
@@ -2641,11 +2708,6 @@ void Viewport::set_use_own_world(bool p_world) {
if (is_inside_tree())
_propagate_exit_world(this);
-#ifndef _3D_DISABLED
- if (find_world().is_valid() && camera)
- camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
-#endif
-
if (!p_world)
own_world = Ref<World>();
else
@@ -2654,13 +2716,6 @@ void Viewport::set_use_own_world(bool p_world) {
if (is_inside_tree())
_propagate_enter_world(this);
-#ifndef _3D_DISABLED
- if (find_world().is_valid() && camera)
- camera->notification(Camera::NOTIFICATION_BECAME_CURRENT);
-#endif
-
- //propagate exit
-
if (is_inside_tree()) {
VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
}
@@ -2684,6 +2739,19 @@ Rect2 Viewport::get_attach_to_screen_rect() const {
return to_screen_rect;
}
+void Viewport::set_use_render_direct_to_screen(bool p_render_direct_to_screen) {
+
+ if (p_render_direct_to_screen == render_direct_to_screen)
+ return;
+
+ render_direct_to_screen = p_render_direct_to_screen;
+ VS::get_singleton()->viewport_set_render_direct_to_screen(viewport, p_render_direct_to_screen);
+}
+
+bool Viewport::is_using_render_direct_to_screen() const {
+ return render_direct_to_screen;
+}
+
void Viewport::set_physics_object_picking(bool p_enable) {
physics_object_picking = p_enable;
@@ -2862,6 +2930,13 @@ bool Viewport::is_handling_input_locally() const {
return handle_input_locally;
}
+void Viewport::_validate_property(PropertyInfo &property) const {
+
+ if (VisualServer::get_singleton()->is_low_end() && property.name == "hdr") {
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+}
+
void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &Viewport::set_use_arvr);
@@ -2942,6 +3017,8 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
ClassDB::bind_method(D_METHOD("set_attach_to_screen_rect", "rect"), &Viewport::set_attach_to_screen_rect);
+ ClassDB::bind_method(D_METHOD("set_use_render_direct_to_screen", "enable"), &Viewport::set_use_render_direct_to_screen);
+ ClassDB::bind_method(D_METHOD("is_using_render_direct_to_screen"), &Viewport::is_using_render_direct_to_screen);
ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position);
ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse);
@@ -2996,6 +3073,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_3d_linear"), "set_keep_3d_linear", "get_keep_3d_linear");
ADD_PROPERTY(PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_ENUM, "2D,2D No-Sampling,3D,3D No-Effects"), "set_usage", "get_usage");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_direct_to_screen"), "set_use_render_direct_to_screen", "is_using_render_direct_to_screen");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
ADD_GROUP("Render Target", "render_target_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_target_v_flip"), "set_vflip", "get_vflip");
@@ -3078,6 +3156,8 @@ Viewport::Viewport() {
texture_rid = VisualServer::get_singleton()->viewport_get_texture(viewport);
texture_flags = 0;
+ render_direct_to_screen = false;
+
default_texture.instance();
default_texture->vp = const_cast<Viewport *>(this);
viewport_textures.insert(default_texture.ptr());
@@ -3132,7 +3212,7 @@ Viewport::Viewport() {
gui.tooltip_timer = -1;
//gui.tooltip_timer->force_parent_owned();
- gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.7);
+ 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::REAL, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
gui.tooltip = NULL;
@@ -3141,6 +3221,8 @@ Viewport::Viewport() {
gui.drag_attempted = false;
gui.canvas_sort_index = 0;
gui.roots_order_dirty = false;
+ gui.mouse_focus = NULL;
+ gui.last_mouse_focus = NULL;
msaa = MSAA_DISABLED;
hdr = true;
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 0565fd3d18..b7160d5139 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -182,6 +182,7 @@ private:
Size2 size;
Rect2 to_screen_rect;
+ bool render_direct_to_screen;
RID contact_2d_debug;
RID contact_3d_debug_multimesh;
@@ -221,12 +222,11 @@ private:
} physics_last_mouse_state;
- void _collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape, bool p_discard_empty_motion);
+ void _collision_object_input_event(CollisionObject *p_object, Camera *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;
- void _test_new_mouseover(ObjectID new_collider);
Map<ObjectID, uint64_t> physics_2d_mouseover;
Ref<World2D> world_2d;
@@ -305,6 +305,8 @@ private:
bool disable_input;
void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input);
+ void _gui_call_notification(Control *p_control, int p_what);
+
void _gui_prepare_subwindows();
void _gui_sort_subwindows();
void _gui_sort_roots();
@@ -382,10 +384,14 @@ private:
void _canvas_layer_remove(CanvasLayer *p_canvas_layer);
void _drop_mouse_focus();
+ void _drop_physics_mouseover();
+
+ void _update_canvas_items(Node *p_node);
protected:
void _notification(int p_what);
static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const;
public:
Listener *get_listener() const;
@@ -401,6 +407,7 @@ public:
bool is_audio_listener_2d() const;
void set_size(const Size2 &p_size);
+ void update_canvas_items();
Size2 get_size() const;
Rect2 get_visible_rect() const;
@@ -475,6 +482,9 @@ public:
void set_attach_to_screen_rect(const Rect2 &p_rect);
Rect2 get_attach_to_screen_rect() const;
+ void set_use_render_direct_to_screen(bool p_render_direct_to_screen);
+ bool is_using_render_direct_to_screen() const;
+
Vector2 get_mouse_position() const;
void warp_mouse(const Vector2 &p_pos);