diff options
-rw-r--r-- | source/blender/modifiers/intern/MOD_nodes.cc | 52 | ||||
-rw-r--r-- | source/blender/nodes/NOD_derived_node_tree.hh | 20 | ||||
-rw-r--r-- | source/blender/nodes/NOD_node_tree_ref.hh | 26 | ||||
-rw-r--r-- | source/blender/nodes/intern/derived_node_tree.cc | 40 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_tree_ref.cc | 90 |
5 files changed, 162 insertions, 66 deletions
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 72842a1d32d..267c4be5571 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -89,6 +89,7 @@ using blender::bke::PersistentCollectionHandle; using blender::bke::PersistentDataHandleMap; using blender::bke::PersistentObjectHandle; using blender::fn::GMutablePointer; +using blender::fn::GPointer; using blender::fn::GValueMap; using blender::nodes::GeoNodeExecParams; using namespace blender::fn::multi_function_types; @@ -253,6 +254,9 @@ static bool isDisabled(const struct Scene *UNUSED(scene), } class GeometryNodesEvaluator { + public: + using LogSocketValueFn = std::function<void(DSocket, Span<GPointer>)>; + private: blender::LinearAllocator<> allocator_; Map<std::pair<DInputSocket, DOutputSocket>, GMutablePointer> value_by_input_; @@ -263,6 +267,7 @@ class GeometryNodesEvaluator { const Object *self_object_; const ModifierData *modifier_; Depsgraph *depsgraph_; + LogSocketValueFn log_socket_value_fn_; public: GeometryNodesEvaluator(const Map<DOutputSocket, GMutablePointer> &group_input_data, @@ -271,16 +276,19 @@ class GeometryNodesEvaluator { const PersistentDataHandleMap &handle_map, const Object *self_object, const ModifierData *modifier, - Depsgraph *depsgraph) + Depsgraph *depsgraph, + LogSocketValueFn log_socket_value_fn) : group_outputs_(std::move(group_outputs)), mf_by_node_(mf_by_node), conversions_(blender::nodes::get_implicit_type_conversions()), handle_map_(handle_map), self_object_(self_object), modifier_(modifier), - depsgraph_(depsgraph) + depsgraph_(depsgraph), + log_socket_value_fn_(std::move(log_socket_value_fn)) { for (auto item : group_input_data.items()) { + this->log_socket_value(item.key, item.value); this->forward_to_inputs(item.key, item.value); } } @@ -290,6 +298,7 @@ class GeometryNodesEvaluator { Vector<GMutablePointer> results; for (const DInputSocket &group_output : group_outputs_) { Vector<GMutablePointer> result = this->get_input_values(group_output); + this->log_socket_value(group_output, result); results.append(result[0]); } for (GMutablePointer value : value_by_input_.values()) { @@ -384,7 +393,9 @@ class GeometryNodesEvaluator { GValueMap<StringRef> node_inputs_map{allocator_}; for (const InputSocketRef *input_socket : node->inputs()) { if (input_socket->is_available()) { - Vector<GMutablePointer> values = this->get_input_values({node.context(), input_socket}); + DInputSocket dsocket{node.context(), input_socket}; + Vector<GMutablePointer> values = this->get_input_values(dsocket); + this->log_socket_value(dsocket, values); for (int i = 0; i < values.size(); ++i) { /* Values from Multi Input Sockets are stored in input map with the format * <identifier>[<index>]. */ @@ -404,12 +415,31 @@ class GeometryNodesEvaluator { /* Forward computed outputs to linked input sockets. */ for (const OutputSocketRef *output_socket : node->outputs()) { if (output_socket->is_available()) { + const DOutputSocket dsocket{node.context(), output_socket}; GMutablePointer value = node_outputs_map.extract(output_socket->identifier()); - this->forward_to_inputs({node.context(), output_socket}, value); + this->log_socket_value(dsocket, value); + this->forward_to_inputs(dsocket, value); } } } + void log_socket_value(const DSocket socket, Span<GPointer> values) + { + if (log_socket_value_fn_) { + log_socket_value_fn_(socket, values); + } + } + + void log_socket_value(const DSocket socket, Span<GMutablePointer> values) + { + this->log_socket_value(socket, values.cast<GPointer>()); + } + + void log_socket_value(const DSocket socket, GPointer value) + { + this->log_socket_value(socket, Span<GPointer>(&value, 1)); + } + void execute_node(const DNode node, GeoNodeExecParams params) { const bNode &bnode = params.node(); @@ -523,8 +553,15 @@ class GeometryNodesEvaluator { { /* For all sockets that are linked with the from_socket push the value to their node. */ Vector<DInputSocket> to_sockets_all; - from_socket.foreach_target_socket( - [&](DInputSocket to_socket) { to_sockets_all.append_non_duplicates(to_socket); }); + + auto handle_target_socket_fn = [&](DInputSocket to_socket) { + to_sockets_all.append_non_duplicates(to_socket); + }; + auto handle_skipped_socket_fn = [&, this](DSocket socket) { + this->log_socket_value(socket, value_to_forward); + }; + + from_socket.foreach_target_socket(handle_target_socket_fn, handle_skipped_socket_fn); const CPPType &from_type = *value_to_forward.type(); Vector<DInputSocket> to_sockets_same_type; @@ -1112,7 +1149,8 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, handle_map, ctx->object, (ModifierData *)nmd, - ctx->depsgraph}; + ctx->depsgraph, + {}}; Vector<GMutablePointer> results = evaluator.execute(); BLI_assert(results.size() == 1); diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index c29de611e18..e294bef2ea8 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -59,6 +59,7 @@ class DTreeContext { const NodeTreeRef *tree_; /* All the children contexts of this context. */ Map<const NodeRef *, DTreeContext *> children_; + DerivedNodeTree *derived_tree_; friend DerivedNodeTree; @@ -67,6 +68,7 @@ class DTreeContext { const DTreeContext *parent_context() const; const NodeRef *parent_node() const; const DTreeContext *child_context(const NodeRef &node) const; + const DerivedNodeTree &derived_tree() const; bool is_root() const; }; @@ -117,6 +119,8 @@ class DSocket { operator bool() const; uint64_t hash() const; + + DNode node() const; }; /* A (nullable) reference to an input socket and the context it is in. */ @@ -132,7 +136,7 @@ class DInputSocket : public DSocket { DOutputSocket get_corresponding_group_node_output() const; Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const; - void foreach_origin_socket(FunctionRef<void(DSocket)> callback) const; + void foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const; }; /* A (nullable) reference to an output socket and the context it is in. */ @@ -148,7 +152,8 @@ class DOutputSocket : public DSocket { DInputSocket get_corresponding_group_node_input() const; DInputSocket get_active_corresponding_group_output_socket() const; - void foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const; + void foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn, + FunctionRef<void(DSocket)> skipped_fn) const; }; class DerivedNodeTree { @@ -214,6 +219,11 @@ inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) cons return children_.lookup_default(&node, nullptr); } +inline const DerivedNodeTree &DTreeContext::derived_tree() const +{ + return *derived_tree_; +} + inline bool DTreeContext::is_root() const { return parent_context_ == nullptr; @@ -319,6 +329,12 @@ inline uint64_t DSocket::hash() const return get_default_hash_2(context_, socket_ref_); } +inline DNode DSocket::node() const +{ + BLI_assert(socket_ref_ != nullptr); + return {context_, &socket_ref_->node()}; +} + /* -------------------------------------------------------------------- * DInputSocket inline methods. */ diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh index 3710bd2fe00..f4c5d277f16 100644 --- a/source/blender/nodes/NOD_node_tree_ref.hh +++ b/source/blender/nodes/NOD_node_tree_ref.hh @@ -81,15 +81,19 @@ class SocketRef : NonCopyable, NonMovable { Vector<LinkRef *> directly_linked_links_; /* These sockets are linked directly, i.e. with a single link in between. */ - MutableSpan<SocketRef *> directly_linked_sockets_; + MutableSpan<const SocketRef *> directly_linked_sockets_; /* These sockets are linked when reroutes, muted links and muted nodes have been taken into * account. */ - MutableSpan<SocketRef *> logically_linked_sockets_; + MutableSpan<const SocketRef *> logically_linked_sockets_; + /* These are the sockets that have been skipped when searching for logicaly linked sockets. That + * includes for example the input and output socket of an intermediate reroute node. */ + MutableSpan<const SocketRef *> logically_linked_skipped_sockets_; friend NodeTreeRef; public: Span<const SocketRef *> logically_linked_sockets() const; + Span<const SocketRef *> logically_linked_skipped_sockets() const; Span<const SocketRef *> directly_linked_sockets() const; Span<const LinkRef *> directly_linked_links() const; @@ -132,12 +136,19 @@ class InputSocketRef final : public SocketRef { Span<const OutputSocketRef *> directly_linked_sockets() const; bool is_multi_input_socket() const; + + void foreach_logical_origin(FunctionRef<void(const OutputSocketRef &)> origin_fn, + FunctionRef<void(const SocketRef &)> skipped_fn, + bool only_follow_first_input_link = false) const; }; class OutputSocketRef final : public SocketRef { public: Span<const InputSocketRef *> logically_linked_sockets() const; Span<const InputSocketRef *> directly_linked_sockets() const; + + void foreach_logical_target(FunctionRef<void(const InputSocketRef &)> target_fn, + FunctionRef<void(const SocketRef &)> skipped_fn) const; }; class NodeRef : NonCopyable, NonMovable { @@ -257,12 +268,6 @@ class NodeTreeRef : NonCopyable, NonMovable { bNodeSocket *bsocket); void create_linked_socket_caches(); - - void foreach_logical_origin(InputSocketRef &socket, - FunctionRef<void(OutputSocketRef &)> callback, - bool only_follow_first_input_link = false); - void foreach_logical_target(OutputSocketRef &socket, - FunctionRef<void(InputSocketRef &)> callback); }; using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>; @@ -287,6 +292,11 @@ inline Span<const SocketRef *> SocketRef::logically_linked_sockets() const return logically_linked_sockets_; } +inline Span<const SocketRef *> SocketRef::logically_linked_skipped_sockets() const +{ + return logically_linked_skipped_sockets_; +} + inline Span<const SocketRef *> SocketRef::directly_linked_sockets() const { return directly_linked_sockets_; diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index e4f8a0c5fda..cfa790780f2 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -40,6 +40,7 @@ DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *paren DTreeContext &context = *allocator_.construct<DTreeContext>().release(); context.parent_context_ = parent_context; context.parent_node_ = parent_node; + context.derived_tree_ = this; context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree); used_node_tree_refs_.add(context.tree_); @@ -167,10 +168,10 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const return {}; } -/* Call the given callback for every "real" origin socket. "Real" means that reroutes, muted nodes +/* Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes * and node groups are handled by this function. Origin sockets are ones where a node gets its * inputs from. */ -void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback) const +void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const { BLI_assert(*this); for (const OutputSocketRef *linked_socket : socket_ref_->as_input().logically_linked_sockets()) { @@ -180,18 +181,18 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback) co if (linked_node.is_group_input_node()) { if (context_->is_root()) { /* This is a group input in the root node group. */ - callback(linked_dsocket); + origin_fn(linked_dsocket); } else { DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input(); if (socket_in_parent_group->is_logically_linked()) { /* Follow the links coming into the corresponding socket on the parent group node. */ - socket_in_parent_group.foreach_origin_socket(callback); + socket_in_parent_group.foreach_origin_socket(origin_fn); } else { /* The corresponding input on the parent group node is not connected. Therefore, we use * the value of that input socket directly. */ - callback(socket_in_parent_group); + origin_fn(socket_in_parent_group); } } } @@ -200,27 +201,32 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback) co if (socket_in_group) { if (socket_in_group->is_logically_linked()) { /* Follow the links coming into the group output node of the child node group. */ - socket_in_group.foreach_origin_socket(callback); + socket_in_group.foreach_origin_socket(origin_fn); } else { /* The output of the child node group is not connected, so we have to get the value from * that socket. */ - callback(socket_in_group); + origin_fn(socket_in_group); } } } else { /* The normal case: just use the value of a linked output socket. */ - callback(linked_dsocket); + origin_fn(linked_dsocket); } } } -/* Calls the given callback for every "real" target socket. "Real" means that reroutes, muted nodes +/* Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes * and node groups are handled by this function. Target sockets are on the nodes that use the value - * from this socket. */ -void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const + * from this socket. The `skipped_fn` function is called for sockets that have been skipped during + * the search for target sockets (e.g. reroutes). */ +void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn, + FunctionRef<void(DSocket)> skipped_fn) const { + for (const SocketRef *skipped_socket : socket_ref_->logically_linked_skipped_sockets()) { + skipped_fn.call_safe({context_, skipped_socket}); + } for (const InputSocketRef *linked_socket : socket_ref_->as_output().logically_linked_sockets()) { const NodeRef &linked_node = linked_socket->node(); DInputSocket linked_dsocket{context_, linked_socket}; @@ -228,26 +234,30 @@ void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callba if (linked_node.is_group_output_node()) { if (context_->is_root()) { /* This is a group output in the root node group. */ - callback(linked_dsocket); + target_fn(linked_dsocket); } else { /* Follow the links going out of the group node in the parent node group. */ DOutputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_output(); - socket_in_parent_group.foreach_target_socket(callback); + skipped_fn.call_safe(linked_dsocket); + skipped_fn.call_safe(socket_in_parent_group); + socket_in_parent_group.foreach_target_socket(target_fn, skipped_fn); } } else if (linked_node.is_group_node()) { /* Follow the links within the nested node group. */ Vector<DOutputSocket> sockets_in_group = linked_dsocket.get_corresponding_group_input_sockets(); + skipped_fn.call_safe(linked_dsocket); for (DOutputSocket socket_in_group : sockets_in_group) { - socket_in_group.foreach_target_socket(callback); + skipped_fn.call_safe(socket_in_group); + socket_in_group.foreach_target_socket(target_fn, skipped_fn); } } else { /* The normal case: just use the linked input socket as target. */ - callback(linked_dsocket); + target_fn(linked_dsocket); } } } diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index e627a7f4497..d9ae594a860 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -163,7 +163,7 @@ void NodeTreeRef::create_linked_socket_caches() { for (InputSocketRef *socket : input_sockets_) { /* Find directly linked socket based on incident links. */ - Vector<SocketRef *> directly_linked_sockets; + Vector<const SocketRef *> directly_linked_sockets; for (LinkRef *link : socket->directly_linked_links_) { directly_linked_sockets.append(link->from_); } @@ -171,9 +171,11 @@ void NodeTreeRef::create_linked_socket_caches() directly_linked_sockets.as_span()); /* Find logically linked sockets. */ - Vector<SocketRef *> logically_linked_sockets; - this->foreach_logical_origin( - *socket, [&](OutputSocketRef &origin) { logically_linked_sockets.append(&origin); }); + Vector<const SocketRef *> logically_linked_sockets; + Vector<const SocketRef *> logically_linked_skipped_sockets; + socket->foreach_logical_origin( + [&](const OutputSocketRef &origin) { logically_linked_sockets.append(&origin); }, + [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }); if (logically_linked_sockets == directly_linked_sockets) { socket->logically_linked_sockets_ = socket->directly_linked_sockets_; } @@ -181,11 +183,13 @@ void NodeTreeRef::create_linked_socket_caches() socket->logically_linked_sockets_ = allocator_.construct_array_copy( logically_linked_sockets.as_span()); } + socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy( + logically_linked_skipped_sockets.as_span()); } for (OutputSocketRef *socket : output_sockets_) { /* Find directly linked socket based on incident links. */ - Vector<SocketRef *> directly_linked_sockets; + Vector<const SocketRef *> directly_linked_sockets; for (LinkRef *link : socket->directly_linked_links_) { directly_linked_sockets.append(link->to_); } @@ -193,9 +197,11 @@ void NodeTreeRef::create_linked_socket_caches() directly_linked_sockets.as_span()); /* Find logically linked sockets. */ - Vector<SocketRef *> logically_linked_sockets; - this->foreach_logical_target( - *socket, [&](InputSocketRef &target) { logically_linked_sockets.append(&target); }); + Vector<const SocketRef *> logically_linked_sockets; + Vector<const SocketRef *> logically_linked_skipped_sockets; + socket->foreach_logical_target( + [&](const InputSocketRef &target) { logically_linked_sockets.append(&target); }, + [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }); if (logically_linked_sockets == directly_linked_sockets) { socket->logically_linked_sockets_ = socket->directly_linked_sockets_; } @@ -203,61 +209,77 @@ void NodeTreeRef::create_linked_socket_caches() socket->logically_linked_sockets_ = allocator_.construct_array_copy( logically_linked_sockets.as_span()); } + socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy( + logically_linked_skipped_sockets.as_span()); } } -void NodeTreeRef::foreach_logical_origin(InputSocketRef &socket, - FunctionRef<void(OutputSocketRef &)> callback, - bool only_follow_first_input_link) +void InputSocketRef::foreach_logical_origin(FunctionRef<void(const OutputSocketRef &)> origin_fn, + FunctionRef<void(const SocketRef &)> skipped_fn, + bool only_follow_first_input_link) const { - Span<LinkRef *> links_to_check = socket.directly_linked_links_; + Span<const LinkRef *> links_to_check = this->directly_linked_links(); if (only_follow_first_input_link) { links_to_check = links_to_check.take_front(1); } - for (LinkRef *link : links_to_check) { + for (const LinkRef *link : links_to_check) { if (link->is_muted()) { continue; } - OutputSocketRef *origin = link->from_; - NodeRef *origin_node = origin->node_; - if (origin_node->is_reroute_node()) { - this->foreach_logical_origin(*origin_node->inputs_[0], callback, false); + const OutputSocketRef &origin = link->from(); + const NodeRef &origin_node = origin.node(); + if (origin_node.is_reroute_node()) { + const InputSocketRef &reroute_input = origin_node.input(0); + const OutputSocketRef &reroute_output = origin_node.output(0); + skipped_fn.call_safe(reroute_input); + skipped_fn.call_safe(reroute_output); + reroute_input.foreach_logical_origin(origin_fn, skipped_fn, false); } - else if (origin_node->is_muted()) { - for (InternalLinkRef *internal_link : origin_node->internal_links_) { - if (internal_link->to_ == origin) { - this->foreach_logical_origin(*internal_link->from_, callback, true); + else if (origin_node.is_muted()) { + for (const InternalLinkRef *internal_link : origin_node.internal_links()) { + if (&internal_link->to() == &origin) { + const InputSocketRef &mute_input = internal_link->from(); + skipped_fn.call_safe(origin); + skipped_fn.call_safe(mute_input); + mute_input.foreach_logical_origin(origin_fn, skipped_fn, true); break; } } } else { - callback(*origin); + origin_fn(origin); } } } -void NodeTreeRef::foreach_logical_target(OutputSocketRef &socket, - FunctionRef<void(InputSocketRef &)> callback) +void OutputSocketRef::foreach_logical_target(FunctionRef<void(const InputSocketRef &)> target_fn, + FunctionRef<void(const SocketRef &)> skipped_fn) const { - for (LinkRef *link : socket.directly_linked_links_) { + for (const LinkRef *link : this->directly_linked_links()) { if (link->is_muted()) { continue; } - InputSocketRef *target = link->to_; - NodeRef *target_node = target->node_; - if (target_node->is_reroute_node()) { - this->foreach_logical_target(*target_node->outputs_[0], callback); + const InputSocketRef &target = link->to(); + const NodeRef &target_node = target.node(); + if (target_node.is_reroute_node()) { + const OutputSocketRef &reroute_output = target_node.output(0); + skipped_fn.call_safe(target); + skipped_fn.call_safe(reroute_output); + reroute_output.foreach_logical_target(target_fn, skipped_fn); } - else if (target_node->is_muted()) { - for (InternalLinkRef *internal_link : target_node->internal_links_) { - if (internal_link->from_ == target) { - this->foreach_logical_target(*internal_link->to_, callback); + else if (target_node.is_muted()) { + skipped_fn.call_safe(target); + for (const InternalLinkRef *internal_link : target_node.internal_links()) { + if (&internal_link->from() == &target) { + const OutputSocketRef &mute_output = internal_link->to(); + skipped_fn.call_safe(target); + skipped_fn.call_safe(mute_output); + mute_output.foreach_logical_target(target_fn, skipped_fn); } } } else { - callback(*target); + target_fn(target); } } } |