summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2021-06-16 17:26:12 +0200
committerGitHub <noreply@github.com>2021-06-16 17:26:12 +0200
commitad28a03b4bbce7ee83950e31177ab384bb54cfd8 (patch)
treed315bfef09feda5eae316aa5c785826ba7a296ca /scene
parent479737538b23ff36e81e9e1f6294464bba913e31 (diff)
parent38d164c74b24f10215312f304ec1b04175989376 (diff)
Merge pull request #49632 from reduz/refactor-visibility-notifier-2d
Refactor VisibilityNotifier2D
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/audio_stream_player_2d.cpp6
-rw-r--r--scene/2d/visibility_notifier_2d.cpp300
-rw-r--r--scene/2d/visibility_notifier_2d.h45
-rw-r--r--scene/main/viewport.cpp12
-rw-r--r--scene/resources/world_2d.cpp287
-rw-r--r--scene/resources/world_2d.h14
6 files changed, 101 insertions, 563 deletions
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<Viewport *> viewports;
Ref<World2D> 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<Viewport *>::Element *E = viewports.front(); E; E = E->next()) {
+ const Set<Viewport *> viewports = world_2d->get_viewports();
+
+ for (Set<Viewport *>::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<Node *, Variant>::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<Node *, Variant>::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<RigidBody2D>(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<AnimationPlayer>(p_node);
- if (ap) {
- add = true;
- }
- }
-
- {
- AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
- if (as) {
- add = true;
- }
- }
-
- {
- GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
- if (ps) {
- add = true;
- }
+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;
+}
- 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);
+void VisibilityEnabler2D::set_enable_node_path(NodePath p_path) {
+ if (enable_node_path == p_path) {
+ return;
}
-
- 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
+ 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<Node *>(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);
}
-
- _find_nodes(c);
}
}
-
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<Node *, Variant>::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();
- }
-}
-
-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<RigidBody2D>(p_node);
- if (rb) {
- rb->set_sleeping(!p_enabled);
- }
- }
-
- if (enabler[ENABLER_PAUSE_ANIMATIONS]) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
-
- if (ap) {
- ap->set_active(p_enabled);
- }
- }
-
- if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) {
- AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
-
- if (as) {
- if (p_enabled) {
- as->play();
- } else {
- as->stop();
- }
- }
- }
-
- if (enabler[ENABLER_PAUSE_PARTICLES]) {
- GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
-
- if (ps) {
- ps->set_emitting(p_enabled);
- }
- }
-}
-
-void VisibilityEnabler2D::_node_removed(Node *p_node) {
- if (!visible) {
- _change_node_state(p_node, true);
+ node_id = ObjectID();
}
- nodes.erase(p_node);
-}
-
-TypedArray<String> VisibilityEnabler2D::get_configuration_warnings() const {
- TypedArray<String> 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;
-protected:
- friend struct SpatialIndexer2D;
-
- void _enter_viewport(Viewport *p_viewport);
- void _exit_viewport(Viewport *p_viewport);
+private:
+ bool on_screen = false;
+ void _visibility_enter();
+ void _visibility_exit();
+protected:
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<Node *, Variant> 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();
+ void _update_enable_mode(bool p_enable);
+
public:
- void set_enabler(Enabler p_enabler, bool p_enable);
- bool is_enabler_enabled(Enabler p_enabler) const;
+ void set_enable_mode(EnableMode p_mode);
+ EnableMode get_enable_mode();
- TypedArray<String> get_configuration_warnings() const override;
+ 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<World2D> &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<World2D> &p_world_2d) {
if (is_inside_tree()) {
current_canvas = find_world_2d()->get_canvas();
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
- find_world_2d()->_register_viewport(this, Rect2());
}
}
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<VisibilityNotifier2D *, CellRef> notifiers;
- };
-
- Map<CellKey, CellData> cells;
- int cell_size;
-
- Map<VisibilityNotifier2D *, Rect2> notifiers;
-
- struct ViewportData {
- Map<VisibilityNotifier2D *, uint64_t> notifiers;
- Rect2 rect;
- };
-
- Map<Viewport *, ViewportData> 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<CellKey, CellData>::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<VisibilityNotifier2D *, Rect2>::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<VisibilityNotifier2D *, Rect2>::Element *E = notifiers.find(p_notifier);
- ERR_FAIL_COND(!E);
- _notifier_update_cells(p_notifier, E->get(), false);
- notifiers.erase(p_notifier);
-
- List<Viewport *> removed;
- for (Map<Viewport *, ViewportData>::Element *F = viewports.front(); F; F = F->next()) {
- Map<VisibilityNotifier2D *, uint64_t>::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<Viewport *, ViewportData>::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<VisibilityNotifier2D *> removed;
- for (Map<VisibilityNotifier2D *, uint64_t>::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<Viewport *, ViewportData>::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<VisibilityNotifier2D *> added;
- List<VisibilityNotifier2D *> 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<CellKey, CellData>::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<VisibilityNotifier2D *, CellRef>::Element *G = F->get().notifiers.front(); G; G = G->next()) {
- Map<VisibilityNotifier2D *, uint64_t>::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<CellKey, CellData>::Element *F = cells.find(ck);
- if (!F) {
- continue;
- }
-
- //notifiers in cell
- for (Map<VisibilityNotifier2D *, CellRef>::Element *G = F->get().notifiers.front(); G; G = G->next()) {
- Map<VisibilityNotifier2D *, uint64_t>::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<VisibilityNotifier2D *, uint64_t>::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<Viewport *> *r_viewports) {
- for (Map<Viewport *, SpatialIndexer2D::ViewportData>::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<Viewport *> 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<Viewport *> *r_viewports);
+ _FORCE_INLINE_ const Set<Viewport *> &get_viewports() { return viewports; }
World2D();
~World2D();