Node3D and CanvasItem children change to LocalVector

This commit is contained in:
lawnjelly 2025-06-13 10:04:27 +01:00
parent 46c495ca21
commit af2b9be356
4 changed files with 91 additions and 33 deletions

View file

@ -108,12 +108,15 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) {
return; return;
} }
for (Node3D *&E : data.children) { for (uint32_t n = 0; n < data.node3d_children.size(); n++) {
if (E->data.top_level) { Node3D *s = data.node3d_children[n];
continue; //don't propagate to a top_level
// Don't propagate to a toplevel.
if (!s->data.top_level) {
s->_propagate_transform_changed(p_origin);
} }
E->_propagate_transform_changed(p_origin);
} }
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if ((!data.gizmos.is_empty() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) { if ((!data.gizmos.is_empty() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
#else #else
@ -148,9 +151,11 @@ void Node3D::_notification(int p_what) {
} }
if (data.parent) { if (data.parent) {
data.C = data.parent->data.children.push_back(this); data.index_in_parent = data.parent->data.node3d_children.size();
} else { data.parent->data.node3d_children.push_back(this);
data.C = nullptr; } else if (data.index_in_parent != UINT32_MAX) {
data.index_in_parent = UINT32_MAX;
ERR_PRINT("Node3D ENTER_TREE detected without EXIT_TREE, recovering.");
} }
if (data.top_level && !Engine::get_singleton()->is_editor_hint()) { if (data.top_level && !Engine::get_singleton()->is_editor_hint()) {
@ -202,11 +207,27 @@ void Node3D::_notification(int p_what) {
if (xform_change.in_list()) { if (xform_change.in_list()) {
get_tree()->xform_change_list.remove(&xform_change); get_tree()->xform_change_list.remove(&xform_change);
} }
if (data.C) {
data.parent->data.children.erase(data.C); if (data.parent) {
if (data.index_in_parent != UINT32_MAX) {
// Aliases
uint32_t c = data.index_in_parent;
LocalVector<Node3D *> &parent_children = data.parent->data.node3d_children;
parent_children.remove_at_unordered(c);
// After unordered remove, we need to inform the moved child
// what their new id is in the parent children list.
if (parent_children.size() > c) {
parent_children[c]->data.index_in_parent = c;
}
} else {
ERR_PRINT("Node3D index_in_parent unset at EXIT_TREE.");
}
} }
data.index_in_parent = UINT32_MAX;
data.parent = nullptr; data.parent = nullptr;
data.C = nullptr;
_update_visibility_parent(true); _update_visibility_parent(true);
_disable_client_physics_interpolation(); _disable_client_physics_interpolation();
} break; } break;
@ -1063,11 +1084,12 @@ void Node3D::_propagate_visibility_changed() {
} }
#endif #endif
for (Node3D *c : data.children) { for (uint32_t n = 0; n < data.node3d_children.size(); n++) {
if (!c || !c->data.visible) { Node3D *s = data.node3d_children[n];
continue;
if (s->data.visible) {
s->_propagate_visibility_changed();
} }
c->_propagate_visibility_changed();
} }
} }
@ -1312,7 +1334,7 @@ void Node3D::_update_visibility_parent(bool p_update_root) {
RS::get_singleton()->instance_set_visibility_parent(vi->get_instance(), data.visibility_parent); RS::get_singleton()->instance_set_visibility_parent(vi->get_instance(), data.visibility_parent);
} }
for (Node3D *c : data.children) { for (Node3D *c : data.node3d_children) {
c->_update_visibility_parent(false); c->_update_visibility_parent(false);
} }
} }

View file

@ -153,8 +153,12 @@ private:
RID visibility_parent; RID visibility_parent;
Node3D *parent = nullptr; Node3D *parent = nullptr;
List<Node3D *> children;
List<Node3D *>::Element *C = nullptr; // An unordered vector of `Spatial` children only.
// This is a subset of the `Node::children`, purely
// an optimization for faster traversal.
LocalVector<Node3D *> node3d_children;
uint32_t index_in_parent = UINT32_MAX;
ClientPhysicsInterpolationData *client_physics_interpolation_data = nullptr; ClientPhysicsInterpolationData *client_physics_interpolation_data = nullptr;

View file

@ -317,8 +317,15 @@ void CanvasItem::_notification(int p_what) {
if (ci) { if (ci) {
parent_visible_in_tree = ci->is_visible_in_tree(); parent_visible_in_tree = ci->is_visible_in_tree();
C = ci->children_items.push_back(this);
data.index_in_parent = ci->data.canvas_item_children.size();
ci->data.canvas_item_children.push_back(this);
} else { } else {
if (data.index_in_parent != UINT32_MAX) {
data.index_in_parent = UINT32_MAX;
ERR_PRINT("CanvasItem ENTER_TREE detected without EXIT_TREE, recovering.");
}
CanvasLayer *cl = Object::cast_to<CanvasLayer>(parent); CanvasLayer *cl = Object::cast_to<CanvasLayer>(parent);
if (cl) { if (cl) {
@ -388,10 +395,27 @@ void CanvasItem::_notification(int p_what) {
get_tree()->xform_change_list.remove(&xform_change); get_tree()->xform_change_list.remove(&xform_change);
} }
_exit_canvas(); _exit_canvas();
if (C) {
Object::cast_to<CanvasItem>(get_parent())->children_items.erase(C); CanvasItem *parent = Object::cast_to<CanvasItem>(get_parent());
C = nullptr; if (parent) {
if (data.index_in_parent != UINT32_MAX) {
// Aliases
uint32_t c = data.index_in_parent;
LocalVector<CanvasItem *> &parent_children = parent->data.canvas_item_children;
parent_children.remove_at_unordered(c);
// After unordered remove, we need to inform the moved child
// what their new id is in the parent children list.
if (parent_children.size() > c) {
parent_children[c]->data.index_in_parent = c;
}
} else {
ERR_PRINT("CanvasItem index_in_parent unset at EXIT_TREE.");
}
} }
data.index_in_parent = UINT32_MAX;
if (window) { if (window) {
window->disconnect(SceneStringName(visibility_changed), callable_mp(this, &CanvasItem::_window_visibility_changed)); window->disconnect(SceneStringName(visibility_changed), callable_mp(this, &CanvasItem::_window_visibility_changed));
window = nullptr; window = nullptr;
@ -1056,11 +1080,11 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) {
} }
} }
for (CanvasItem *ci : p_node->children_items) { for (uint32_t n = 0; n < p_node->data.canvas_item_children.size(); n++) {
if (ci->top_level) { CanvasItem *ci = p_node->data.canvas_item_children[n];
continue; if (!ci->top_level) {
_notify_transform(ci);
} }
_notify_transform(ci);
} }
} }
@ -1611,9 +1635,11 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
_update_self_texture_filter(texture_filter_cache); _update_self_texture_filter(texture_filter_cache);
if (p_propagate) { if (p_propagate) {
for (CanvasItem *E : children_items) { for (uint32_t n = 0; n < data.canvas_item_children.size(); n++) {
if (!E->top_level && E->texture_filter == TEXTURE_FILTER_PARENT_NODE) { CanvasItem *ci = data.canvas_item_children[n];
E->_update_texture_filter_changed(true);
if (!ci->top_level && ci->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
ci->_update_texture_filter_changed(true);
} }
} }
} }
@ -1665,9 +1691,10 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
_update_self_texture_repeat(texture_repeat_cache); _update_self_texture_repeat(texture_repeat_cache);
if (p_propagate) { if (p_propagate) {
for (CanvasItem *E : children_items) { for (uint32_t n = 0; n < data.canvas_item_children.size(); n++) {
if (!E->top_level && E->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) { CanvasItem *ci = data.canvas_item_children[n];
E->_update_texture_repeat_changed(true); if (!ci->top_level && ci->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
ci->_update_texture_repeat_changed(true);
} }
} }
} }

View file

@ -83,8 +83,13 @@ private:
Color modulate = Color(1, 1, 1, 1); Color modulate = Color(1, 1, 1, 1);
Color self_modulate = Color(1, 1, 1, 1); Color self_modulate = Color(1, 1, 1, 1);
List<CanvasItem *> children_items; struct Data {
List<CanvasItem *>::Element *C = nullptr; // An unordered vector of `CanvasItem` children only.
// This is a subset of the `Node::children`, purely
// an optimization for faster traversal.
LocalVector<CanvasItem *> canvas_item_children;
uint32_t index_in_parent = UINT32_MAX;
} data;
int light_mask = 1; int light_mask = 1;
uint32_t visibility_layer = 1; uint32_t visibility_layer = 1;