Fix #106235: use first non-dangling link of multi-input socket for internal link

Pull Request: https://projects.blender.org/blender/blender/pulls/119280
This commit is contained in:
Iliya Katueshenock
2024-03-11 15:39:02 +01:00
committed by Jacques Lucke
parent c388ed1e53
commit 95810eec8f
@@ -616,6 +616,25 @@ class NodeTreeMainUpdater {
return false;
}
struct InternalLink {
bNodeSocket *from;
bNodeSocket *to;
int multi_input_socket_index = 0;
BLI_STRUCT_EQUALITY_OPERATORS_3(InternalLink, from, to, multi_input_socket_index);
};
const bNodeLink *first_non_dangling_link(const bNodeTree &ntree,
const Span<const bNodeLink *> links) const
{
for (const bNodeLink *link : links) {
if (!bke::nodeIsDanglingReroute(&ntree, link->fromnode)) {
return link;
}
}
return nullptr;
}
void update_internal_links(bNodeTree &ntree)
{
bke::node_tree_runtime::AllowUsingOutdatedInfo allow_outdated_info{ntree};
@@ -625,7 +644,7 @@ class NodeTreeMainUpdater {
continue;
}
/* Find all expected internal links. */
Vector<std::pair<bNodeSocket *, bNodeSocket *>> expected_internal_links;
Vector<InternalLink> expected_internal_links;
for (const bNodeSocket *output_socket : node->output_sockets()) {
if (!output_socket->is_available()) {
continue;
@@ -637,31 +656,40 @@ class NodeTreeMainUpdater {
continue;
}
const bNodeSocket *input_socket = this->find_internally_linked_input(output_socket);
if (input_socket != nullptr) {
expected_internal_links.append(
{const_cast<bNodeSocket *>(input_socket), const_cast<bNodeSocket *>(output_socket)});
if (input_socket == nullptr) {
continue;
}
const Span<const bNodeLink *> connected_links = input_socket->directly_linked_links();
const bNodeLink *connected_link = first_non_dangling_link(ntree, connected_links);
const int index = connected_link ? connected_link->multi_input_socket_index :
std::max<int>(0, connected_links.size() - 1);
expected_internal_links.append(InternalLink{const_cast<bNodeSocket *>(input_socket),
const_cast<bNodeSocket *>(output_socket),
index});
}
/* Rebuilt internal links if they have changed. */
if (node->runtime->internal_links.size() != expected_internal_links.size()) {
this->update_internal_links_in_node(ntree, *node, expected_internal_links);
continue;
}
else {
for (auto &item : expected_internal_links) {
const bNodeSocket *from_socket = item.first;
const bNodeSocket *to_socket = item.second;
bool found = false;
for (const bNodeLink &internal_link : node->runtime->internal_links) {
if (from_socket == internal_link.fromsock && to_socket == internal_link.tosock) {
found = true;
}
}
if (!found) {
this->update_internal_links_in_node(ntree, *node, expected_internal_links);
break;
}
}
const bool all_expected_internal_links_exist = std::all_of(
node->runtime->internal_links.begin(),
node->runtime->internal_links.end(),
[&](const bNodeLink &link) {
const InternalLink internal_link{
link.fromsock, link.tosock, link.multi_input_socket_index};
return expected_internal_links.as_span().contains(internal_link);
});
if (all_expected_internal_links_exist) {
continue;
}
this->update_internal_links_in_node(ntree, *node, expected_internal_links);
}
}
@@ -701,18 +729,17 @@ class NodeTreeMainUpdater {
void update_internal_links_in_node(bNodeTree &ntree,
bNode &node,
Span<std::pair<bNodeSocket *, bNodeSocket *>> links)
Span<InternalLink> internal_links)
{
node.runtime->internal_links.clear();
node.runtime->internal_links.reserve(links.size());
for (const auto &item : links) {
bNodeSocket *from_socket = item.first;
bNodeSocket *to_socket = item.second;
node.runtime->internal_links.reserve(internal_links.size());
for (const InternalLink &internal_link : internal_links) {
bNodeLink link{};
link.fromnode = &node;
link.fromsock = from_socket;
link.fromsock = internal_link.from;
link.tonode = &node;
link.tosock = to_socket;
link.tosock = internal_link.to;
link.multi_input_socket_index = internal_link.multi_input_socket_index;
link.flag |= NODE_LINK_VALID;
node.runtime->internal_links.append(link);
}