Files
test2/source/blender/nodes/intern/geometry_nodes_closure.cc
Jacques Lucke 21d603895e Refactor: Geometry Nodes: support detection of syncable closure/bundle nodes
This is extracted from #140967.

Previously, it was possible to sync a bundle/closure node based on what's linked.
However, it was not possible to detect if the syncing was possible or necessary
in the first place. Knowing this helps building UI features that inform the user
about outdated nodes.
2025-07-02 07:38:30 +02:00

134 lines
4.2 KiB
C++

/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_node_runtime.hh"
#include "NOD_geometry_nodes_closure.hh"
namespace blender::nodes {
std::optional<int> ClosureSignature::find_input_index(const SocketInterfaceKey &key) const
{
for (const int i : this->inputs.index_range()) {
const Item &item = this->inputs[i];
if (item.key.matches(key)) {
return i;
}
}
return std::nullopt;
}
std::optional<int> ClosureSignature::find_output_index(const SocketInterfaceKey &key) const
{
for (const int i : this->outputs.index_range()) {
const Item &item = this->outputs[i];
if (item.key.matches(key)) {
return i;
}
}
return std::nullopt;
}
static bool items_equal(const ClosureSignature::Item &a, const ClosureSignature::Item &b)
{
if (!a.key.matches_exactly(b.key)) {
return false;
}
if (a.type != b.type) {
return false;
}
if (a.structure_type.has_value() && b.structure_type.has_value()) {
if (*a.structure_type != *b.structure_type) {
return false;
}
}
return true;
}
bool ClosureSignature::matches_exactly(const ClosureSignature &other) const
{
if (inputs.size() != other.inputs.size()) {
return false;
}
if (outputs.size() != other.outputs.size()) {
return false;
}
for (const Item &item : inputs) {
if (std::none_of(other.inputs.begin(), other.inputs.end(), [&](const Item &other_item) {
return items_equal(item, other_item);
}))
{
return false;
}
}
for (const Item &item : outputs) {
if (std::none_of(other.outputs.begin(), other.outputs.end(), [&](const Item &other_item) {
return items_equal(item, other_item);
}))
{
return false;
}
}
return true;
}
bool ClosureSignature::all_matching_exactly(const Span<ClosureSignature> signatures)
{
if (signatures.is_empty()) {
return true;
}
for (const ClosureSignature &signature : signatures.drop_front(1)) {
if (!signatures[0].matches_exactly(signature)) {
return false;
}
}
return true;
}
ClosureSignature ClosureSignature::FromClosureOutputNode(const bNode &node)
{
BLI_assert(node.is_type("GeometryNodeClosureOutput"));
const auto &storage = *static_cast<const NodeGeometryClosureOutput *>(node.storage);
nodes::ClosureSignature signature;
for (const int i : IndexRange(storage.input_items.items_num)) {
const NodeGeometryClosureInputItem &item = storage.input_items.items[i];
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
signature.inputs.append({nodes::SocketInterfaceKey(item.name), stype});
}
}
for (const int i : IndexRange(storage.output_items.items_num)) {
const NodeGeometryClosureOutputItem &item = storage.output_items.items[i];
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
signature.outputs.append({nodes::SocketInterfaceKey(item.name), stype});
}
}
return signature;
}
ClosureSignature ClosureSignature::FromEvaluateClosureNode(const bNode &node)
{
BLI_assert(node.is_type("GeometryNodeEvaluateClosure"));
const auto &storage = *static_cast<const NodeGeometryEvaluateClosure *>(node.storage);
nodes::ClosureSignature signature;
for (const int i : IndexRange(storage.input_items.items_num)) {
const NodeGeometryEvaluateClosureInputItem &item = storage.input_items.items[i];
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
signature.inputs.append({nodes::SocketInterfaceKey(item.name),
stype,
nodes::StructureType(item.structure_type)});
}
}
for (const int i : IndexRange(storage.output_items.items_num)) {
const NodeGeometryEvaluateClosureOutputItem &item = storage.output_items.items[i];
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
signature.outputs.append({nodes::SocketInterfaceKey(item.name),
stype,
nodes::StructureType(item.structure_type)});
}
}
return signature;
}
} // namespace blender::nodes