Bläddra i källkod

Merge pull request #107324 from lawnjelly/is_vis_in_tree

[3.x] Pre-calculate `is_visible_in_tree()`
lawnjelly 2 månader sedan
förälder
incheckning
67265bacd5
2 ändrade filer med 56 tillägg och 2 borttagningar
  1. 43 1
      scene/3d/spatial.cpp
  2. 13 1
      scene/3d/spatial.h

+ 43 - 1
scene/3d/spatial.cpp

@@ -158,6 +158,7 @@ void Spatial::_notification(int p_what) {
 			} else {
 				data.C = nullptr;
 			}
+			_update_visible_in_tree();
 
 			if (data.toplevel && !Engine::get_singleton()->is_editor_hint()) {
 				if (data.parent) {
@@ -217,6 +218,8 @@ void Spatial::_notification(int p_what) {
 			data.parent = nullptr;
 			data.C = nullptr;
 			data.toplevel_active = false;
+
+			_update_visible_in_tree();
 			_disable_client_physics_interpolation();
 		} break;
 		case NOTIFICATION_ENTER_WORLD: {
@@ -818,6 +821,36 @@ Ref<World> Spatial::get_world() const {
 	return data.viewport->find_world();
 }
 
+void Spatial::_update_visible_in_tree() {
+	Spatial *parent = get_parent_spatial();
+
+	bool propagate_visible = parent ? parent->data.visible_in_tree : true;
+
+	// Only propagate visible when entering tree if we are visible.
+	propagate_visible &= is_visible();
+
+	_propagate_visible_in_tree(propagate_visible);
+}
+
+void Spatial::_propagate_visible_in_tree(bool p_visible_in_tree) {
+	// If any node is invisible, the propagation changes to invisible below.
+	p_visible_in_tree &= is_visible();
+
+	// No change.
+	if (data.visible_in_tree == p_visible_in_tree) {
+		return;
+	}
+
+	data.visible_in_tree = p_visible_in_tree;
+
+	for (int32_t n = 0; n < get_child_count(); n++) {
+		Spatial *s = Object::cast_to<Spatial>(get_child(n));
+		if (s) {
+			s->_propagate_visible_in_tree(p_visible_in_tree);
+		}
+	}
+}
+
 void Spatial::_propagate_visibility_changed() {
 	notification(NOTIFICATION_VISIBILITY_CHANGED);
 	emit_signal(SceneStringNames::get_singleton()->visibility_changed);
@@ -877,6 +910,10 @@ void Spatial::show() {
 		return;
 	}
 
+	bool parent_visible = get_parent_spatial() ? get_parent_spatial()->data.visible_in_tree : true;
+	if (parent_visible) {
+		_propagate_visible_in_tree(true);
+	}
 	_propagate_visibility_changed();
 }
 
@@ -891,10 +928,14 @@ void Spatial::hide() {
 		return;
 	}
 
+	bool parent_visible = get_parent_spatial() ? get_parent_spatial()->data.visible_in_tree : true;
+	if (parent_visible) {
+		_propagate_visible_in_tree(false);
+	}
 	_propagate_visibility_changed();
 }
 
-bool Spatial::is_visible_in_tree() const {
+bool Spatial::_is_visible_in_tree_reference() const {
 	const Spatial *s = this;
 
 	while (s) {
@@ -1207,6 +1248,7 @@ Spatial::Spatial() :
 	data.viewport = nullptr;
 	data.inside_world = false;
 	data.visible = true;
+	data.visible_in_tree = true;
 	data.disable_scale = false;
 	data.vi_visible = true;
 	data.merging_allowed = true;

+ 13 - 1
scene/3d/spatial.h

@@ -121,6 +121,7 @@ private:
 		bool notify_transform : 1;
 
 		bool visible : 1;
+		bool visible_in_tree : 1;
 		bool disable_scale : 1;
 
 		// Scene tree interpolation
@@ -155,6 +156,9 @@ private:
 	void _notify_dirty();
 	void _propagate_transform_changed(Spatial *p_origin);
 
+	void _update_visible_in_tree();
+	bool _is_visible_in_tree_reference() const;
+	void _propagate_visible_in_tree(bool p_visible_in_tree);
 	void _propagate_visibility_changed();
 	void _propagate_merging_allowed(bool p_merging_allowed);
 
@@ -293,7 +297,15 @@ public:
 	bool is_visible() const;
 	void show();
 	void hide();
-	bool is_visible_in_tree() const;
+	bool is_visible_in_tree() const {
+#if DEV_ENABLED
+		// As this is newly introduced, regression test the old method against the new in DEV builds.
+		// If no regressions, this can be removed after a beta.
+		bool visible = _is_visible_in_tree_reference();
+		ERR_FAIL_COND_V_MSG(data.visible_in_tree != visible, visible, "is_visible_in_tree regression detected, recovering.");
+#endif
+		return data.visible_in_tree;
+	}
 
 	void force_update_transform();