diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 25df918522..757f0691bf 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1616,9 +1616,6 @@ If [code]true[/code], XR support is enabled in Godot, this ensures required shaders are compiled. - - Cell size used for the 2D hash grid that [VisibilityNotifier2D] uses (in pixels). - diff --git a/doc/classes/VisibilityEnabler2D.xml b/doc/classes/VisibilityEnabler2D.xml index 02fe7a7cd0..8eb16ba075 100644 --- a/doc/classes/VisibilityEnabler2D.xml +++ b/doc/classes/VisibilityEnabler2D.xml @@ -1,79 +1,25 @@ - Enables certain nodes only when approximately visible. - The VisibilityEnabler2D will disable [RigidBody2D], [AnimationPlayer], and other nodes when they are not visible. It will only affect nodes with the same root node as the VisibilityEnabler2D, and the root node itself. - If you just want to receive notifications, use [VisibilityNotifier2D] instead. - [b]Note:[/b] For performance reasons, VisibilityEnabler2D uses an approximate heuristic with precision determined by [member ProjectSettings.world/2d/cell_size]. If you need precise visibility checking, use another method such as adding an [Area2D] node as a child of a [Camera2D] node. - [b]Note:[/b] VisibilityEnabler2D will not affect nodes added after scene initialization. - - - - - - - Returns whether the enabler identified by given [enum Enabler] constant is active. - - - - - - - - - - - Sets active state of the enabler identified by given [enum Enabler] constant. - - - - If [code]true[/code], [RigidBody2D] nodes will be paused. + - - If [code]true[/code], [AnimatedSprite2D] nodes will be paused. - - - If [code]true[/code], [AnimationPlayer] nodes will be paused. - - - If [code]true[/code], [GPUParticles2D] nodes will be paused. - - - If [code]true[/code], the parent's [method Node._physics_process] will be stopped. - - - If [code]true[/code], the parent's [method Node._process] will be stopped. + - - This enabler will pause [AnimationPlayer] nodes. + - - This enabler will freeze [RigidBody2D] nodes. + - - This enabler will stop [GPUParticles2D] nodes. - - - This enabler will stop the parent's _process function. - - - This enabler will stop the parent's _physics_process function. - - - This enabler will stop [AnimatedSprite2D] nodes animations. - - - Represents the size of the [enum Enabler] enum. + diff --git a/doc/classes/VisibilityNotifier2D.xml b/doc/classes/VisibilityNotifier2D.xml index 761438b77e..78983e74ee 100644 --- a/doc/classes/VisibilityNotifier2D.xml +++ b/doc/classes/VisibilityNotifier2D.xml @@ -1,12 +1,11 @@ - Detects approximately when the node is visible on screen. + Detects when the node extents are visible on screen. The VisibilityNotifier2D detects when it is visible on the screen. It also notifies when its bounding rectangle enters or exits the screen or a viewport. If you want nodes to be disabled automatically when they exit the screen, use [VisibilityEnabler2D] instead. - [b]Note:[/b] For performance reasons, VisibilityNotifier2D uses an approximate heuristic with precision determined by [member ProjectSettings.world/2d/cell_size]. If you need precise visibility checking, use another method such as adding an [Area2D] node as a child of a [Camera2D] node. https://godotengine.org/asset-library/asset/515 @@ -37,20 +36,6 @@ Emitted when the VisibilityNotifier2D exits the screen. - - - - - Emitted when the VisibilityNotifier2D enters a [Viewport]'s view. - - - - - - - Emitted when the VisibilityNotifier2D exits a [Viewport]'s view. - - diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 6d8d6058eb..127ef6762d 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -170,7 +170,6 @@ void AudioStreamPlayer2D::_notification(int p_what) { //update anything related to position first, if possible of course if (!output_ready.is_set()) { - List viewports; Ref world_2d = get_world_2d(); ERR_FAIL_COND(world_2d.is_null()); @@ -203,8 +202,9 @@ void AudioStreamPlayer2D::_notification(int p_what) { break; } - world_2d->get_viewport_list(&viewports); - for (List::Element *E = viewports.front(); E; E = E->next()) { + const Set viewports = world_2d->get_viewports(); + + for (Set::Element *E = viewports.front(); E; E = E->next()) { Viewport *vp = E->get(); if (vp->is_audio_listener_2d()) { //compute matrix to convert to screen diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index c85b2c85a4..a73d60ada5 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -48,46 +48,29 @@ bool VisibilityNotifier2D::_edit_use_rect() const { } #endif -void VisibilityNotifier2D::_enter_viewport(Viewport *p_viewport) { - ERR_FAIL_COND(viewports.has(p_viewport)); - viewports.insert(p_viewport); - - if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) { +void VisibilityNotifier2D::_visibility_enter() { + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { return; } - if (viewports.size() == 1) { - emit_signal(SceneStringNames::get_singleton()->screen_entered); - - _screen_enter(); - } - emit_signal(SceneStringNames::get_singleton()->viewport_entered, p_viewport); + on_screen = true; + emit_signal(SceneStringNames::get_singleton()->screen_entered); + _screen_enter(); } - -void VisibilityNotifier2D::_exit_viewport(Viewport *p_viewport) { - ERR_FAIL_COND(!viewports.has(p_viewport)); - viewports.erase(p_viewport); - - if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) { +void VisibilityNotifier2D::_visibility_exit() { + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { return; } - emit_signal(SceneStringNames::get_singleton()->viewport_exited, p_viewport); - if (viewports.size() == 0) { - emit_signal(SceneStringNames::get_singleton()->screen_exited); - - _screen_exit(); - } + on_screen = false; + emit_signal(SceneStringNames::get_singleton()->screen_exited); + _screen_exit(); } void VisibilityNotifier2D::set_rect(const Rect2 &p_rect) { rect = p_rect; if (is_inside_tree()) { - get_world_2d()->_update_notifier(this, get_global_transform().xform(rect)); - if (Engine::get_singleton()->is_editor_hint()) { - update(); - item_rect_changed(); - } + RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibilityNotifier2D::_visibility_enter), callable_mp(this, &VisibilityNotifier2D::_visibility_exit)); } } @@ -99,11 +82,8 @@ void VisibilityNotifier2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { //get_world_2d()-> - get_world_2d()->_register_notifier(this, get_global_transform().xform(rect)); - } break; - case NOTIFICATION_TRANSFORM_CHANGED: { - //get_world_2d()-> - get_world_2d()->_update_notifier(this, get_global_transform().xform(rect)); + on_screen = false; + RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibilityNotifier2D::_visibility_enter), callable_mp(this, &VisibilityNotifier2D::_visibility_exit)); } break; case NOTIFICATION_DRAW: { if (Engine::get_singleton()->is_editor_hint()) { @@ -111,13 +91,14 @@ void VisibilityNotifier2D::_notification(int p_what) { } } break; case NOTIFICATION_EXIT_TREE: { - get_world_2d()->_remove_notifier(this); + on_screen = false; + RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), false, Rect2(), Callable(), Callable()); } break; } } bool VisibilityNotifier2D::is_on_screen() const { - return viewports.size() > 0; + return on_screen; } void VisibilityNotifier2D::_bind_methods() { @@ -127,235 +108,106 @@ void VisibilityNotifier2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::RECT2, "rect"), "set_rect", "get_rect"); - ADD_SIGNAL(MethodInfo("viewport_entered", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport"))); - ADD_SIGNAL(MethodInfo("viewport_exited", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport"))); ADD_SIGNAL(MethodInfo("screen_entered")); ADD_SIGNAL(MethodInfo("screen_exited")); } VisibilityNotifier2D::VisibilityNotifier2D() { rect = Rect2(-10, -10, 20, 20); - set_notify_transform(true); } ////////////////////////////////////// void VisibilityEnabler2D::_screen_enter() { - for (Map::Element *E = nodes.front(); E; E = E->next()) { - _change_node_state(E->key(), true); - } - - if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) { - get_parent()->set_physics_process(true); - } - if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) { - get_parent()->set_process(true); - } - - visible = true; + _update_enable_mode(true); } void VisibilityEnabler2D::_screen_exit() { - for (Map::Element *E = nodes.front(); E; E = E->next()) { - _change_node_state(E->key(), false); - } - - if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) { - get_parent()->set_physics_process(false); - } - if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) { - get_parent()->set_process(false); - } - - visible = false; + _update_enable_mode(false); } -void VisibilityEnabler2D::_find_nodes(Node *p_node) { - bool add = false; - Variant meta; - - { - RigidBody2D *rb2d = Object::cast_to(p_node); - if (rb2d && ((rb2d->get_mode() == RigidBody2D::MODE_DYNAMIC || rb2d->get_mode() == RigidBody2D::MODE_DYNAMIC_LOCKED))) { - add = true; - meta = rb2d->get_mode(); - } - } - - { - AnimationPlayer *ap = Object::cast_to(p_node); - if (ap) { - add = true; - } - } - - { - AnimatedSprite2D *as = Object::cast_to(p_node); - if (as) { - add = true; - } - } - - { - GPUParticles2D *ps = Object::cast_to(p_node); - if (ps) { - add = true; - } - } - - if (add) { - p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler2D::_node_removed), varray(p_node), CONNECT_ONESHOT); - nodes[p_node] = meta; - _change_node_state(p_node, false); - } - - for (int i = 0; i < p_node->get_child_count(); i++) { - Node *c = p_node->get_child(i); - if (c->get_filename() != String()) { - continue; //skip, instance - } - - _find_nodes(c); +void VisibilityEnabler2D::set_enable_mode(EnableMode p_mode) { + enable_mode = p_mode; + if (is_inside_tree()) { + _update_enable_mode(is_on_screen()); } } +VisibilityEnabler2D::EnableMode VisibilityEnabler2D::get_enable_mode() { + return enable_mode; +} +void VisibilityEnabler2D::set_enable_node_path(NodePath p_path) { + if (enable_node_path == p_path) { + return; + } + enable_node_path = p_path; + if (is_inside_tree()) { + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + _update_enable_mode(is_on_screen()); + } + } +} +NodePath VisibilityEnabler2D::get_enable_node_path() { + return enable_node_path; +} + +void VisibilityEnabler2D::_update_enable_mode(bool p_enable) { + Node *node = static_cast(ObjectDB::get_instance(node_id)); + if (node) { + if (p_enable) { + switch (enable_mode) { + case ENABLE_MODE_INHERIT: { + node->set_process_mode(PROCESS_MODE_INHERIT); + } break; + case ENABLE_MODE_ALWAYS: { + node->set_process_mode(PROCESS_MODE_ALWAYS); + } break; + case ENABLE_MODE_WHEN_PAUSED: { + node->set_process_mode(PROCESS_MODE_WHEN_PAUSED); + } break; + } + } else { + node->set_process_mode(PROCESS_MODE_DISABLED); + } + } +} void VisibilityEnabler2D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { if (Engine::get_singleton()->is_editor_hint()) { return; } - Node *from = this; - //find where current scene starts - while (from->get_parent() && from->get_filename() == String()) { - from = from->get_parent(); - } - - _find_nodes(from); - - // We need to defer the call of set_process and set_physics_process, - // otherwise they are overwritten inside NOTIFICATION_READY. - // We can't use call_deferred, because it happens after a physics frame. - // The ready signal works as it's emitted immediately after NOTIFICATION_READY. - - if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) { - get_parent()->connect(SceneStringNames::get_singleton()->ready, - callable_mp(get_parent(), &Node::set_physics_process), varray(false), CONNECT_ONESHOT); - } - if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) { - get_parent()->connect(SceneStringNames::get_singleton()->ready, - callable_mp(get_parent(), &Node::set_process), varray(false), CONNECT_ONESHOT); + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + node->set_process_mode(PROCESS_MODE_DISABLED); } } if (p_what == NOTIFICATION_EXIT_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } - - for (Map::Element *E = nodes.front(); E; E = E->next()) { - if (!visible) { - _change_node_state(E->key(), true); - } - E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler2D::_node_removed)); - } - - nodes.clear(); + node_id = ObjectID(); } } -void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) { - ERR_FAIL_COND(!nodes.has(p_node)); - - if (enabler[ENABLER_FREEZE_BODIES]) { - RigidBody2D *rb = Object::cast_to(p_node); - if (rb) { - rb->set_sleeping(!p_enabled); - } - } - - if (enabler[ENABLER_PAUSE_ANIMATIONS]) { - AnimationPlayer *ap = Object::cast_to(p_node); - - if (ap) { - ap->set_active(p_enabled); - } - } - - if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) { - AnimatedSprite2D *as = Object::cast_to(p_node); - - if (as) { - if (p_enabled) { - as->play(); - } else { - as->stop(); - } - } - } - - if (enabler[ENABLER_PAUSE_PARTICLES]) { - GPUParticles2D *ps = Object::cast_to(p_node); - - if (ps) { - ps->set_emitting(p_enabled); - } - } -} - -void VisibilityEnabler2D::_node_removed(Node *p_node) { - if (!visible) { - _change_node_state(p_node, true); - } - nodes.erase(p_node); -} - -TypedArray VisibilityEnabler2D::get_configuration_warnings() const { - TypedArray warnings = Node::get_configuration_warnings(); - -#ifdef TOOLS_ENABLED - if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) { - warnings.push_back(TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent.")); - } -#endif - return warnings; -} - void VisibilityEnabler2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler2D::set_enabler); - ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler2D::is_enabler_enabled); - ClassDB::bind_method(D_METHOD("_node_removed"), &VisibilityEnabler2D::_node_removed); + ClassDB::bind_method(D_METHOD("set_enable_mode", "mode"), &VisibilityEnabler2D::set_enable_mode); + ClassDB::bind_method(D_METHOD("get_enable_mode"), &VisibilityEnabler2D::get_enable_mode); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animations"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATIONS); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "freeze_bodies"), "set_enabler", "is_enabler_enabled", ENABLER_FREEZE_BODIES); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_particles"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_PARTICLES); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animated_sprites"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATED_SPRITES); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "process_parent"), "set_enabler", "is_enabler_enabled", ENABLER_PARENT_PROCESS); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "physics_process_parent"), "set_enabler", "is_enabler_enabled", ENABLER_PARENT_PHYSICS_PROCESS); + ClassDB::bind_method(D_METHOD("set_enable_node_path", "path"), &VisibilityEnabler2D::set_enable_node_path); + ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibilityEnabler2D::get_enable_node_path); - BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS); - BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES); - BIND_ENUM_CONSTANT(ENABLER_PAUSE_PARTICLES); - BIND_ENUM_CONSTANT(ENABLER_PARENT_PROCESS); - BIND_ENUM_CONSTANT(ENABLER_PARENT_PHYSICS_PROCESS); - BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATED_SPRITES); - BIND_ENUM_CONSTANT(ENABLER_MAX); -} + ADD_GROUP("Enabling", "enable_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path"); -void VisibilityEnabler2D::set_enabler(Enabler p_enabler, bool p_enable) { - ERR_FAIL_INDEX(p_enabler, ENABLER_MAX); - enabler[p_enabler] = p_enable; -} - -bool VisibilityEnabler2D::is_enabler_enabled(Enabler p_enabler) const { - ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false); - return enabler[p_enabler]; + BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT); + BIND_ENUM_CONSTANT(ENABLE_MODE_ALWAYS); + BIND_ENUM_CONSTANT(ENABLE_MODE_WHEN_PAUSED); } VisibilityEnabler2D::VisibilityEnabler2D() { - for (int i = 0; i < ENABLER_MAX; i++) { - enabler[i] = true; - } - enabler[ENABLER_PARENT_PROCESS] = false; - enabler[ENABLER_PARENT_PHYSICS_PROCESS] = false; } diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h index 7f4a5bc193..8cb0989787 100644 --- a/scene/2d/visibility_notifier_2d.h +++ b/scene/2d/visibility_notifier_2d.h @@ -41,12 +41,12 @@ class VisibilityNotifier2D : public Node2D { Rect2 rect; +private: + bool on_screen = false; + void _visibility_enter(); + void _visibility_exit(); + protected: - friend struct SpatialIndexer2D; - - void _enter_viewport(Viewport *p_viewport); - void _exit_viewport(Viewport *p_viewport); - virtual void _screen_enter() {} virtual void _screen_exit() {} @@ -71,42 +71,35 @@ class VisibilityEnabler2D : public VisibilityNotifier2D { GDCLASS(VisibilityEnabler2D, VisibilityNotifier2D); public: - enum Enabler { - ENABLER_PAUSE_ANIMATIONS, - ENABLER_FREEZE_BODIES, - ENABLER_PAUSE_PARTICLES, - ENABLER_PARENT_PROCESS, - ENABLER_PARENT_PHYSICS_PROCESS, - ENABLER_PAUSE_ANIMATED_SPRITES, - ENABLER_MAX + enum EnableMode { + ENABLE_MODE_INHERIT, + ENABLE_MODE_ALWAYS, + ENABLE_MODE_WHEN_PAUSED, }; protected: + ObjectID node_id; virtual void _screen_enter() override; virtual void _screen_exit() override; - bool visible = false; - - void _find_nodes(Node *p_node); - - Map nodes; - void _node_removed(Node *p_node); - bool enabler[ENABLER_MAX]; - - void _change_node_state(Node *p_node, bool p_enabled); + EnableMode enable_mode = ENABLE_MODE_INHERIT; + NodePath enable_node_path = NodePath(".."); void _notification(int p_what); static void _bind_methods(); -public: - void set_enabler(Enabler p_enabler, bool p_enable); - bool is_enabler_enabled(Enabler p_enabler) const; + void _update_enable_mode(bool p_enable); - TypedArray get_configuration_warnings() const override; +public: + void set_enable_mode(EnableMode p_mode); + EnableMode get_enable_mode(); + + void set_enable_node_path(NodePath p_path); + NodePath get_enable_node_path(); VisibilityEnabler2D(); }; -VARIANT_ENUM_CAST(VisibilityEnabler2D::Enabler); +VARIANT_ENUM_CAST(VisibilityEnabler2D::EnableMode); #endif // VISIBILITY_NOTIFIER_2D_H diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 5369792194..425fbf0d6a 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -188,11 +188,6 @@ void Viewport::update_worlds() { return; } - Rect2 abstracted_rect = Rect2(Vector2(), get_visible_rect().size); - Rect2 xformed_rect = (global_canvas_transform * canvas_transform).affine_inverse().xform(abstracted_rect); - find_world_2d()->_update_viewport(this, xformed_rect); - find_world_2d()->_update(); - find_world_3d()->_update(get_tree()->get_frame()); } @@ -441,8 +436,6 @@ void Viewport::_notification(int p_what) { _update_listener(); _update_listener_2d(); - find_world_2d()->_register_viewport(this, Rect2()); - add_to_group("_viewports"); if (get_tree()->is_debugging_collisions_hint()) { //2D @@ -499,9 +492,6 @@ void Viewport::_notification(int p_what) { } 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); @@ -1156,7 +1146,6 @@ void Viewport::set_world_2d(const Ref &p_world_2d) { } if (is_inside_tree()) { - find_world_2d()->_remove_viewport(this); RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas); } @@ -1172,7 +1161,6 @@ void Viewport::set_world_2d(const Ref &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()); } } diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 0a0742753f..9a7a47f884 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -38,284 +38,6 @@ #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" -struct SpatialIndexer2D { - struct CellRef { - int ref = 0; - - _FORCE_INLINE_ int inc() { - ref++; - return ref; - } - _FORCE_INLINE_ int dec() { - ref--; - return ref; - } - }; - - struct CellKey { - union { - struct { - int32_t x; - int32_t y; - }; - uint64_t key = 0; - }; - - bool operator==(const CellKey &p_key) const { return key == p_key.key; } - _FORCE_INLINE_ bool operator<(const CellKey &p_key) const { - return key < p_key.key; - } - }; - - struct CellData { - Map notifiers; - }; - - Map cells; - int cell_size; - - Map notifiers; - - struct ViewportData { - Map notifiers; - Rect2 rect; - }; - - Map viewports; - - bool changed = false; - - uint64_t pass = 0; - - void _notifier_update_cells(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect, bool p_add) { - Point2i begin = p_rect.position; - begin /= cell_size; - Point2i end = p_rect.position + p_rect.size; - end /= cell_size; - for (int i = begin.x; i <= end.x; i++) { - for (int j = begin.y; j <= end.y; j++) { - CellKey ck; - ck.x = i; - ck.y = j; - Map::Element *E = cells.find(ck); - - if (p_add) { - if (!E) { - E = cells.insert(ck, CellData()); - } - E->get().notifiers[p_notifier].inc(); - } else { - ERR_CONTINUE(!E); - if (E->get().notifiers[p_notifier].dec() == 0) { - E->get().notifiers.erase(p_notifier); - if (E->get().notifiers.is_empty()) { - cells.erase(E); - } - } - } - } - } - } - - void _notifier_add(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) { - ERR_FAIL_COND(notifiers.has(p_notifier)); - notifiers[p_notifier] = p_rect; - _notifier_update_cells(p_notifier, p_rect, true); - changed = true; - } - - void _notifier_update(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) { - Map::Element *E = notifiers.find(p_notifier); - ERR_FAIL_COND(!E); - if (E->get() == p_rect) { - return; - } - - _notifier_update_cells(p_notifier, p_rect, true); - _notifier_update_cells(p_notifier, E->get(), false); - E->get() = p_rect; - changed = true; - } - - void _notifier_remove(VisibilityNotifier2D *p_notifier) { - Map::Element *E = notifiers.find(p_notifier); - ERR_FAIL_COND(!E); - _notifier_update_cells(p_notifier, E->get(), false); - notifiers.erase(p_notifier); - - List removed; - for (Map::Element *F = viewports.front(); F; F = F->next()) { - Map::Element *G = F->get().notifiers.find(p_notifier); - - if (G) { - F->get().notifiers.erase(G); - removed.push_back(F->key()); - } - } - - while (!removed.is_empty()) { - p_notifier->_exit_viewport(removed.front()->get()); - removed.pop_front(); - } - - changed = true; - } - - void _add_viewport(Viewport *p_viewport, const Rect2 &p_rect) { - ERR_FAIL_COND(viewports.has(p_viewport)); - ViewportData vd; - vd.rect = p_rect; - viewports[p_viewport] = vd; - changed = true; - } - - void _update_viewport(Viewport *p_viewport, const Rect2 &p_rect) { - Map::Element *E = viewports.find(p_viewport); - ERR_FAIL_COND(!E); - if (E->get().rect == p_rect) { - return; - } - E->get().rect = p_rect; - changed = true; - } - - void _remove_viewport(Viewport *p_viewport) { - ERR_FAIL_COND(!viewports.has(p_viewport)); - List removed; - for (Map::Element *E = viewports[p_viewport].notifiers.front(); E; E = E->next()) { - removed.push_back(E->key()); - } - - while (!removed.is_empty()) { - removed.front()->get()->_exit_viewport(p_viewport); - removed.pop_front(); - } - - viewports.erase(p_viewport); - } - - void _update() { - if (!changed) { - return; - } - - for (Map::Element *E = viewports.front(); E; E = E->next()) { - Point2i begin = E->get().rect.position; - begin /= cell_size; - Point2i end = E->get().rect.position + E->get().rect.size; - end /= cell_size; - pass++; - List added; - List removed; - - uint64_t visible_cells = (uint64_t)(end.x - begin.x) * (uint64_t)(end.y - begin.y); - - if (visible_cells > 10000) { - //well you zoomed out a lot, it's your problem. To avoid freezing in the for loops below, we'll manually check cell by cell - - for (Map::Element *F = cells.front(); F; F = F->next()) { - const CellKey &ck = F->key(); - - if (ck.x < begin.x || ck.x > end.x) { - continue; - } - if (ck.y < begin.y || ck.y > end.y) { - continue; - } - - //notifiers in cell - for (Map::Element *G = F->get().notifiers.front(); G; G = G->next()) { - Map::Element *H = E->get().notifiers.find(G->key()); - if (!H) { - H = E->get().notifiers.insert(G->key(), pass); - added.push_back(G->key()); - } else { - H->get() = pass; - } - } - } - - } else { - //check cells in grid fashion - for (int i = begin.x; i <= end.x; i++) { - for (int j = begin.y; j <= end.y; j++) { - CellKey ck; - ck.x = i; - ck.y = j; - - Map::Element *F = cells.find(ck); - if (!F) { - continue; - } - - //notifiers in cell - for (Map::Element *G = F->get().notifiers.front(); G; G = G->next()) { - Map::Element *H = E->get().notifiers.find(G->key()); - if (!H) { - H = E->get().notifiers.insert(G->key(), pass); - added.push_back(G->key()); - } else { - H->get() = pass; - } - } - } - } - } - - for (Map::Element *F = E->get().notifiers.front(); F; F = F->next()) { - if (F->get() != pass) { - removed.push_back(F->key()); - } - } - - while (!added.is_empty()) { - added.front()->get()->_enter_viewport(E->key()); - added.pop_front(); - } - - while (!removed.is_empty()) { - E->get().notifiers.erase(removed.front()->get()); - removed.front()->get()->_exit_viewport(E->key()); - removed.pop_front(); - } - } - - changed = false; - } - - SpatialIndexer2D() { - cell_size = GLOBAL_DEF("world/2d/cell_size", 100); - } -}; - -void World2D::_register_viewport(Viewport *p_viewport, const Rect2 &p_rect) { - indexer->_add_viewport(p_viewport, p_rect); -} - -void World2D::_update_viewport(Viewport *p_viewport, const Rect2 &p_rect) { - indexer->_update_viewport(p_viewport, p_rect); -} - -void World2D::_remove_viewport(Viewport *p_viewport) { - indexer->_remove_viewport(p_viewport); -} - -void World2D::_register_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) { - indexer->_notifier_add(p_notifier, p_rect); -} - -void World2D::_update_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) { - indexer->_notifier_update(p_notifier, p_rect); -} - -void World2D::_remove_notifier(VisibilityNotifier2D *p_notifier) { - indexer->_notifier_remove(p_notifier); -} - -void World2D::_update() { - indexer->_update(); -} - RID World2D::get_canvas() const { return canvas; } @@ -328,12 +50,6 @@ RID World2D::get_navigation_map() const { return navigation_map; } -void World2D::get_viewport_list(List *r_viewports) { - for (Map::Element *E = indexer->viewports.front(); E; E = E->next()) { - r_viewports->push_back(E->key()); - } -} - void World2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_canvas"), &World2D::get_canvas); ClassDB::bind_method(D_METHOD("get_space"), &World2D::get_space); @@ -369,13 +85,10 @@ World2D::World2D() { NavigationServer2D::get_singleton()->map_set_active(navigation_map, true); NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 10)); NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 5)); - - indexer = memnew(SpatialIndexer2D); } World2D::~World2D() { RenderingServer::get_singleton()->free(canvas); PhysicsServer2D::get_singleton()->free(space); NavigationServer2D::get_singleton()->free(navigation_map); - memdelete(indexer); } diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index 38abf3d7ad..e31ac22351 100644 --- a/scene/resources/world_2d.h +++ b/scene/resources/world_2d.h @@ -46,23 +46,15 @@ class World2D : public Resource { RID space; RID navigation_map; - SpatialIndexer2D *indexer; + Set viewports; protected: static void _bind_methods(); friend class Viewport; - friend class VisibilityNotifier2D; - void _register_viewport(Viewport *p_viewport, const Rect2 &p_rect); - void _update_viewport(Viewport *p_viewport, const Rect2 &p_rect); + void _register_viewport(Viewport *p_viewport); void _remove_viewport(Viewport *p_viewport); - void _register_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect); - void _update_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect); - void _remove_notifier(VisibilityNotifier2D *p_notifier); - - void _update(); - public: RID get_canvas() const; RID get_space() const; @@ -70,7 +62,7 @@ public: PhysicsDirectSpaceState2D *get_direct_space_state(); - void get_viewport_list(List *r_viewports); + _FORCE_INLINE_ const Set &get_viewports() { return viewports; } World2D(); ~World2D(); diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 6e126ea77e..5703737252 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -104,7 +104,7 @@ void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwnersort_y); } -void _attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from) { +void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) { if (ci->copy_back_buffer) { ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect); } @@ -173,32 +173,44 @@ void _attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCu } } - if (ci->update_when_visible) { - RenderingServerDefault::redraw_request(); - } - - if ((ci->commands != nullptr && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) { + if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) { //something to draw? - ci->final_transform = xform; - ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a); - ci->global_rect_cache = global_rect; - ci->global_rect_cache.position -= p_clip_rect.position; - ci->light_masked = false; - int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; - - if (z_last_list[zidx]) { - z_last_list[zidx]->next = ci; - z_last_list[zidx] = ci; - - } else { - z_list[zidx] = ci; - z_last_list[zidx] = ci; + if (ci->update_when_visible) { + RenderingServerDefault::redraw_request(); } - ci->z_final = p_z; + if (ci->commands != nullptr) { + ci->final_transform = xform; + ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a); + ci->global_rect_cache = global_rect; + ci->global_rect_cache.position -= p_clip_rect.position; + ci->light_masked = false; - ci->next = nullptr; + int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; + + if (z_last_list[zidx]) { + z_last_list[zidx]->next = ci; + z_last_list[zidx] = ci; + + } else { + z_list[zidx] = ci; + z_last_list[zidx] = ci; + } + + ci->z_final = p_z; + + ci->next = nullptr; + } + + if (ci->visibility_notifier) { + if (!ci->visibility_notifier->visible_element.in_list()) { + visibility_notifier_list.add(&ci->visibility_notifier->visible_element); + ci->visibility_notifier->just_visible = true; + } + + ci->visibility_notifier->visible_in_frame = RSG::rasterizer->get_frame_number(); + } } } @@ -215,6 +227,13 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 } Rect2 rect = ci->get_rect(); + + if (ci->visibility_notifier) { + if (ci->visibility_notifier->area.size != Vector2()) { + rect = rect.merge(ci->visibility_notifier->area); + } + } + Transform2D xform = ci->xform; if (snapping_2d_transforms_to_pixel) { xform.elements[2] = xform.elements[2].floor(); @@ -289,7 +308,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 canvas_group_from = z_last_list[zidx]; } - _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); + _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform); } } else { RendererCanvasRender::Item *canvas_group_from = nullptr; @@ -305,7 +324,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 } _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true); } - _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); + _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform); for (int i = 0; i < child_item_count; i++) { if (child_items[i]->behind || use_canvas_group) { continue; @@ -1095,6 +1114,26 @@ void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_ canvas_item->use_parent_material = p_enable; } +void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable) { + Item *canvas_item = canvas_item_owner.getornull(p_item); + ERR_FAIL_COND(!canvas_item); + + if (p_enable) { + if (!canvas_item->visibility_notifier) { + canvas_item->visibility_notifier = visibility_notifier_allocator.alloc(); + } + canvas_item->visibility_notifier->area = p_area; + canvas_item->visibility_notifier->enter_callable = p_enter_callable; + canvas_item->visibility_notifier->exit_callable = p_exit_callable; + + } else { + if (canvas_item->visibility_notifier) { + visibility_notifier_allocator.free(canvas_item->visibility_notifier); + canvas_item->visibility_notifier = nullptr; + } + } +} + void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -1477,6 +1516,44 @@ void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS:: ci->texture_repeat = p_repeat; } +void RendererCanvasCull::update_visibility_notifiers() { + SelfList *E = visibility_notifier_list.first(); + while (E) { + SelfList *N = E->next(); + + Item::VisibilityNotifierData *visibility_notifier = E->self(); + if (visibility_notifier->just_visible) { + visibility_notifier->just_visible = false; + + if (!visibility_notifier->enter_callable.is_null()) { + if (RSG::threaded) { + visibility_notifier->enter_callable.call_deferred(nullptr, 0); + } else { + Callable::CallError ce; + Variant ret; + visibility_notifier->enter_callable.call(nullptr, 0, ret, ce); + } + } + } else { + if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) { + visibility_notifier_list.remove(E); + + if (!visibility_notifier->exit_callable.is_null()) { + if (RSG::threaded) { + visibility_notifier->exit_callable.call_deferred(nullptr, 0); + } else { + Callable::CallError ce; + Variant ret; + visibility_notifier->exit_callable.call(nullptr, 0, ret, ce); + } + } + } + } + + E = N; + } +} + bool RendererCanvasCull::free(RID p_rid) { if (canvas_owner.owns(p_rid)) { Canvas *canvas = canvas_owner.getornull(p_rid); @@ -1531,6 +1608,10 @@ bool RendererCanvasCull::free(RID p_rid) { canvas_item->child_items[i]->parent = RID(); } + if (canvas_item->visibility_notifier != nullptr) { + visibility_notifier_allocator.free(canvas_item->visibility_notifier); + } + /* if (canvas_item->material) { canvas_item->material->owners.erase(canvas_item); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 37391d7c0e..661216cad3 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -31,6 +31,7 @@ #ifndef RENDERING_SERVER_CANVAS_CULL_H #define RENDERING_SERVER_CANVAS_CULL_H +#include "core/templates/paged_allocator.h" #include "renderer_compositor.h" #include "renderer_viewport.h" @@ -55,6 +56,20 @@ public: Vector child_items; + struct VisibilityNotifierData { + Rect2 area; + Callable enter_callable; + Callable exit_callable; + bool just_visible = false; + uint64_t visible_in_frame = 0; + SelfList visible_element; + VisibilityNotifierData() : + visible_element(this) { + } + }; + + VisibilityNotifierData *visibility_notifier = nullptr; + Item() { children_order_dirty = true; E = nullptr; @@ -156,6 +171,11 @@ public: bool sdf_used = false; bool snapping_2d_transforms_to_pixel = false; + PagedAllocator visibility_notifier_allocator; + SelfList::List visibility_notifier_list; + + _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform); + private: void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel); void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort); @@ -224,6 +244,8 @@ public: void canvas_item_set_use_parent_material(RID p_item, bool p_enable); + void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable); + void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false); RID canvas_light_allocate(); @@ -283,6 +305,8 @@ public: void canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter); void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat); + void update_visibility_notifiers(); + bool free(RID p_rid); RendererCanvasCull(); ~RendererCanvasCull(); diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index cd66cd0716..95aa05f6b3 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -117,6 +117,8 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { _draw_margins(); RSG::rasterizer->end_frame(p_swap_buffers); + RSG::canvas->update_visibility_notifiers(); + while (frame_drawn_callbacks.front()) { Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object); if (obj) { @@ -396,6 +398,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) : server_thread = 0; } + RSG::threaded = p_create_thread; RSG::canvas = memnew(RendererCanvasCull); RSG::viewport = memnew(RendererViewport); RendererSceneCull *sr = memnew(RendererSceneCull); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index e4d319ed6c..73373c97bb 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -820,6 +820,8 @@ public: FUNC2(canvas_item_set_use_parent_material, RID, bool) + FUNC5(canvas_item_set_visibility_notifier, RID, bool, const Rect2 &, const Callable &, const Callable &) + FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) FUNCRIDSPLIT(canvas_light) diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp index c0d9988e85..2dda506bac 100644 --- a/servers/rendering/rendering_server_globals.cpp +++ b/servers/rendering/rendering_server_globals.cpp @@ -30,6 +30,8 @@ #include "rendering_server_globals.h" +bool RenderingServerGlobals::threaded = false; + RendererStorage *RenderingServerGlobals::storage = nullptr; RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr; RendererCompositor *RenderingServerGlobals::rasterizer = nullptr; diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h index a28a0f5180..63755e6125 100644 --- a/servers/rendering/rendering_server_globals.h +++ b/servers/rendering/rendering_server_globals.h @@ -41,6 +41,8 @@ class RendererScene; class RenderingServerGlobals { public: + static bool threaded; + static RendererStorage *storage; static RendererCanvasRender *canvas_render; static RendererCompositor *rasterizer; diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 1806f1da18..0cb765ef56 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1301,6 +1301,8 @@ public: virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0; + virtual void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0; + enum CanvasGroupMode { CANVAS_GROUP_MODE_DISABLED, CANVAS_GROUP_MODE_OPAQUE,