diff options
Diffstat (limited to 'source/blender/nodes/intern')
-rw-r--r-- | source/blender/nodes/intern/derived_node_tree.cc | 18 | ||||
-rw-r--r-- | source/blender/nodes/intern/extern_implementations.cc | 35 | ||||
-rw-r--r-- | source/blender/nodes/intern/geometry_nodes_eval_log.cc | 79 | ||||
-rw-r--r-- | source/blender/nodes/intern/math_functions.cc | 12 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_common.cc | 163 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_common.h | 10 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_declaration.cc | 8 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_exec.cc | 2 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_exec.h | 2 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_geometry_exec.cc | 19 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_socket.cc | 108 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_socket_declarations.cc | 184 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_tree_ref.cc | 8 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_util.c | 119 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_util.h | 67 | ||||
-rw-r--r-- | source/blender/nodes/intern/socket_search_link.cc | 199 | ||||
-rw-r--r-- | source/blender/nodes/intern/type_conversions.cc | 347 |
17 files changed, 650 insertions, 730 deletions
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index 8a9386c1137..dc223f07a26 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -20,10 +20,6 @@ namespace blender::nodes { -/* Construct a new derived node tree for a given root node tree. The generated derived node tree - * does not own the used node tree refs (so that those can be used by others as well). The caller - * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the - * derived node tree. */ DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs) { /* Construct all possible contexts immediately. This is significantly cheaper than inlining all @@ -73,9 +69,6 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) context->~DTreeContext(); } -/** - * \return True when there is a link cycle. Unavailable sockets are ignored. - */ bool DerivedNodeTree::has_link_cycles() const { for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { @@ -96,7 +89,6 @@ bool DerivedNodeTree::has_undefined_nodes_or_sockets() const return false; } -/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */ void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const { this->foreach_node_in_context_recursive(*root_context_, callback); @@ -168,7 +160,7 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const const DTreeContext *child_context = context_->child_context(socket_ref_->node()); if (child_context == nullptr) { - /* Can happen when the group node references a non-existant group (e.g. when the group is + /* Can happen when the group node references a non-existent group (e.g. when the group is * linked but the original file is not found). */ return {}; } @@ -184,9 +176,6 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const return {}; } -/* 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)> origin_fn) const { BLI_assert(*this); @@ -233,9 +222,6 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) c } } -/* 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(ForeachTargetSocketFn target_fn) const { TargetSocketPathInfo path_info; @@ -281,7 +267,6 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, mute_output.foreach_target_socket(target_fn, path_info); path_info.sockets.pop_last(); path_info.sockets.pop_last(); - break; } } else if (linked_node->is_group_output_node()) { @@ -343,7 +328,6 @@ static dot::Cluster *get_dot_cluster_for_context( }); } -/* Generates a graph in dot format. The generated graph has all node groups inlined. */ std::string DerivedNodeTree::to_dot() const { dot::DirectedGraph digraph; diff --git a/source/blender/nodes/intern/extern_implementations.cc b/source/blender/nodes/intern/extern_implementations.cc deleted file mode 100644 index 35de319f20b..00000000000 --- a/source/blender/nodes/intern/extern_implementations.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "NOD_socket_declarations.hh" -#include "NOD_socket_declarations_geometry.hh" - -namespace blender::nodes { -#define MAKE_EXTERN_SOCKET_IMPLEMENTATION(TYPE) \ - template class SocketDeclarationBuilder<TYPE>; \ - template TYPE::Builder &NodeDeclarationBuilder::add_input<TYPE>(StringRef, StringRef); \ - template TYPE::Builder &NodeDeclarationBuilder::add_output<TYPE>(StringRef, StringRef); - -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Float) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Int) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Vector) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Bool) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Color) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::String) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Geometry) - -#undef MAKE_EXTERN_SOCKET_IMPLEMENTATION -} // namespace blender::nodes diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index ddd3c991518..e33f6cf345d 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -25,12 +25,15 @@ #include "BLT_translation.h" +#include <chrono> + namespace blender::nodes::geometry_nodes_eval_log { using fn::CPPType; using fn::FieldCPPType; using fn::FieldInput; using fn::GField; +using fn::ValueOrFieldCPPType; ModifierLog::ModifierLog(GeoLogger &logger) : input_geometry_log_(std::move(logger.input_geometry_log_)), @@ -63,6 +66,17 @@ ModifierLog::ModifierLog(GeoLogger &logger) node_with_warning.node); node_log.warnings_.append(node_with_warning.warning); } + + for (NodeWithExecutionTime &node_with_exec_time : local_logger.node_exec_times_) { + NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, + node_with_exec_time.node); + node_log.exec_time_ = node_with_exec_time.exec_time; + } + + for (NodeWithDebugMessage &debug_message : local_logger.node_debug_messages_) { + NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, debug_message.node); + node_log.debug_messages_.append(debug_message.message); + } } } @@ -177,12 +191,14 @@ const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket GFieldValueLog::GFieldValueLog(fn::GField field, bool log_full_field) : type_(field.cpp_type()) { - Set<std::reference_wrapper<const FieldInput>> field_inputs_set; - field.node().foreach_field_input( - [&](const FieldInput &field_input) { field_inputs_set.add(field_input); }); + const std::shared_ptr<const fn::FieldInputs> &field_input_nodes = field.node().field_inputs(); + /* Put the deduplicated field inputs into a vector so that they can be sorted below. */ Vector<std::reference_wrapper<const FieldInput>> field_inputs; - field_inputs.extend(field_inputs_set.begin(), field_inputs_set.end()); + if (field_input_nodes) { + field_inputs.extend(field_input_nodes->deduplicated_nodes.begin(), + field_input_nodes->deduplicated_nodes.end()); + } std::sort( field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) { @@ -417,25 +433,38 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value geometry_set, log_full_geometry); values_.append({copied_sockets, std::move(value_log)}); } - else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) { - GField field = field_type->get_gfield(value.get()); - bool log_full_field = false; - if (!field.node().depends_on_input()) { - /* Always log constant fields so that their value can be shown in socket inspection. - * In the future we can also evaluate the field here and only store the value. */ - log_full_field = true; - } - if (!log_full_field) { - for (const DSocket &socket : sockets) { - if (main_logger_->log_full_sockets_.contains(socket)) { - log_full_field = true; - break; + else if (const ValueOrFieldCPPType *value_or_field_type = + dynamic_cast<const ValueOrFieldCPPType *>(&type)) { + const void *value_or_field = value.get(); + if (value_or_field_type->is_field(value_or_field)) { + GField field = *value_or_field_type->get_field_ptr(value_or_field); + bool log_full_field = false; + if (!field.node().depends_on_input()) { + /* Always log constant fields so that their value can be shown in socket inspection. + * In the future we can also evaluate the field here and only store the value. */ + log_full_field = true; + } + if (!log_full_field) { + for (const DSocket &socket : sockets) { + if (main_logger_->log_full_sockets_.contains(socket)) { + log_full_field = true; + break; + } } } + destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( + std::move(field), log_full_field); + values_.append({copied_sockets, std::move(value_log)}); + } + else { + const CPPType &base_type = value_or_field_type->base_type(); + const void *value = value_or_field_type->get_value_ptr(value_or_field); + void *buffer = allocator_->allocate(base_type.size(), base_type.alignment()); + base_type.copy_construct(value, buffer); + destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>( + GMutablePointer{base_type, buffer}); + values_.append({copied_sockets, std::move(value_log)}); } - destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( - std::move(field), log_full_field); - values_.append({copied_sockets, std::move(value_log)}); } else { void *buffer = allocator_->allocate(type.size(), type.alignment()); @@ -457,4 +486,14 @@ void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::str node_warnings_.append({node, {type, std::move(message)}}); } +void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds exec_time) +{ + node_exec_times_.append({node, exec_time}); +} + +void LocalGeoLogger::log_debug_message(DNode node, std::string message) +{ + node_debug_messages_.append({node, std::move(message)}); +} + } // namespace blender::nodes::geometry_nodes_eval_log diff --git a/source/blender/nodes/intern/math_functions.cc b/source/blender/nodes/intern/math_functions.cc index aa23777b664..00f4f2a3405 100644 --- a/source/blender/nodes/intern/math_functions.cc +++ b/source/blender/nodes/intern/math_functions.cc @@ -127,17 +127,17 @@ const FloatMathOperationInfo *get_float_compare_operation_info(const int operati ((void)0) switch (operation) { - case NODE_FLOAT_COMPARE_LESS_THAN: + case NODE_COMPARE_LESS_THAN: RETURN_OPERATION_INFO("Less Than", "math_less_than"); - case NODE_FLOAT_COMPARE_LESS_EQUAL: + case NODE_COMPARE_LESS_EQUAL: RETURN_OPERATION_INFO("Less Than or Equal", "math_less_equal"); - case NODE_FLOAT_COMPARE_GREATER_THAN: + case NODE_COMPARE_GREATER_THAN: RETURN_OPERATION_INFO("Greater Than", "math_greater_than"); - case NODE_FLOAT_COMPARE_GREATER_EQUAL: + case NODE_COMPARE_GREATER_EQUAL: RETURN_OPERATION_INFO("Greater Than or Equal", "math_greater_equal"); - case NODE_FLOAT_COMPARE_EQUAL: + case NODE_COMPARE_EQUAL: RETURN_OPERATION_INFO("Equal", "math_equal"); - case NODE_FLOAT_COMPARE_NOT_EQUAL: + case NODE_COMPARE_NOT_EQUAL: RETURN_OPERATION_INFO("Not Equal", "math_not_equal"); } diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index b80cedc9352..c302b1081af 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -32,6 +32,7 @@ #include "BLI_set.hh" #include "BLI_stack.hh" #include "BLI_string.h" +#include "BLI_string_ref.hh" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -50,33 +51,33 @@ using blender::Map; using blender::MultiValueMap; using blender::Set; using blender::Stack; +using blender::StringRef; /* -------------------------------------------------------------------- */ /** \name Node Group * \{ */ -bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier) +static bNodeSocket *find_matching_socket(ListBase &sockets, StringRef identifier) { - LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->inputs) { - if (STREQ(sock->identifier, identifier)) { - return sock; + LISTBASE_FOREACH (bNodeSocket *, socket, &sockets) { + if (socket->identifier == identifier) { + return socket; } } return nullptr; } +bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier) +{ + return find_matching_socket(groupnode->inputs, identifier); +} + bNodeSocket *node_group_find_output_socket(bNode *groupnode, const char *identifier) { - LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->outputs) { - if (STREQ(sock->identifier, identifier)) { - return sock; - } - } - return nullptr; + return find_matching_socket(groupnode->outputs, identifier); } -/* groups display their internal tree name as label */ -void node_group_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_group_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Data-Block"), maxlen); } @@ -107,7 +108,7 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis } if (nodetree == grouptree) { - *r_disabled_hint = "Nesting a node group inside of itself is not allowed"; + *r_disabled_hint = TIP_("Nesting a node group inside of itself is not allowed"); return false; } @@ -121,83 +122,84 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis return valid; } -/* used for both group nodes and interface nodes */ -static bNodeSocket *group_verify_socket(bNodeTree *ntree, - bNode *gnode, - bNodeSocket *iosock, - ListBase *verify_lb, - eNodeSocketInOut in_out) +static void add_new_socket_from_interface(bNodeTree &node_tree, + bNode &node, + const bNodeSocket &interface_socket, + const eNodeSocketInOut in_out) { - bNodeSocket *sock; + bNodeSocket *socket = nodeAddSocket(&node_tree, + &node, + in_out, + interface_socket.idname, + interface_socket.identifier, + interface_socket.name); - for (sock = (bNodeSocket *)verify_lb->first; sock; sock = sock->next) { - if (STREQ(sock->identifier, iosock->identifier)) { - break; - } + if (interface_socket.typeinfo->interface_init_socket) { + interface_socket.typeinfo->interface_init_socket( + &node_tree, &interface_socket, &node, socket, "interface"); } - if (sock) { - strcpy(sock->name, iosock->name); +} - const int mask = SOCK_HIDE_VALUE; - sock->flag = (sock->flag & ~mask) | (iosock->flag & mask); +static void update_socket_to_match_interface(bNodeTree &node_tree, + bNode &node, + bNodeSocket &socket_to_update, + const bNodeSocket &interface_socket) +{ + strcpy(socket_to_update.name, interface_socket.name); - /* Update socket type if necessary */ - if (sock->typeinfo != iosock->typeinfo) { - nodeModifySocketType(ntree, gnode, sock, iosock->idname); - /* Flag the tree to make sure link validity is updated after type changes. */ - ntree->update |= NTREE_UPDATE_LINKS; - } + const int mask = SOCK_HIDE_VALUE; + socket_to_update.flag = (socket_to_update.flag & ~mask) | (interface_socket.flag & mask); - if (iosock->typeinfo->interface_verify_socket) { - iosock->typeinfo->interface_verify_socket(ntree, iosock, gnode, sock, "interface"); - } + /* Update socket type if necessary */ + if (socket_to_update.typeinfo != interface_socket.typeinfo) { + nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname); + /* Flag the tree to make sure link validity is updated after type changes. */ + node_tree.update |= NTREE_UPDATE_LINKS; } - else { - sock = nodeAddSocket(ntree, gnode, in_out, iosock->idname, iosock->identifier, iosock->name); - if (iosock->typeinfo->interface_init_socket) { - iosock->typeinfo->interface_init_socket(ntree, iosock, gnode, sock, "interface"); - } + if (interface_socket.typeinfo->interface_verify_socket) { + interface_socket.typeinfo->interface_verify_socket( + &node_tree, &interface_socket, &node, &socket_to_update, "interface"); } - - /* remove from list temporarily, to distinguish from orphaned sockets */ - BLI_remlink(verify_lb, sock); - - return sock; } -/* used for both group nodes and interface nodes */ -static void group_verify_socket_list(bNodeTree *ntree, - bNode *gnode, - ListBase *iosock_lb, - ListBase *verify_lb, - eNodeSocketInOut in_out) +/** + * Used for group nodes and group input/output nodes to update the list of input or output sockets + * on a node to match the provided interface. Assumes that \a verify_lb is the node's matching + * input or output socket list, depending on whether the node is a group input/output or a group + * node. + */ +static void group_verify_socket_list(bNodeTree &node_tree, + bNode &node, + const ListBase &interface_sockets, + ListBase &verify_lb, + const eNodeSocketInOut in_out) { - bNodeSocket *sock, *nextsock; - - /* step by step compare */ - - bNodeSocket *iosock = (bNodeSocket *)iosock_lb->first; - for (; iosock; iosock = iosock->next) { - /* abusing new_sock pointer for verification here! only used inside this function */ - iosock->new_sock = group_verify_socket(ntree, gnode, iosock, verify_lb, in_out); - } - /* leftovers are removed */ - for (sock = (bNodeSocket *)verify_lb->first; sock; sock = nextsock) { - nextsock = sock->next; - nodeRemoveSocket(ntree, gnode, sock); - } - /* and we put back the verified sockets */ - iosock = (bNodeSocket *)iosock_lb->first; - for (; iosock; iosock = iosock->next) { - if (iosock->new_sock) { - BLI_addtail(verify_lb, iosock->new_sock); - iosock->new_sock = nullptr; + ListBase old_sockets = verify_lb; + BLI_listbase_clear(&verify_lb); + + LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &interface_sockets) { + bNodeSocket *matching_socket = find_matching_socket(old_sockets, interface_socket->identifier); + if (matching_socket) { + /* If a socket with the same identifier exists in the previous socket list, update it + * with the correct name, type, etc. Then move it from the old list to the new one. */ + update_socket_to_match_interface(node_tree, node, *matching_socket, *interface_socket); + BLI_remlink(&old_sockets, matching_socket); + BLI_addtail(&verify_lb, matching_socket); + } + else { + /* If there was no socket withe the same identifier already, simply create a new socket + * based on the interface socket, which will already add it to the new list. */ + add_new_socket_from_interface(node_tree, node, *interface_socket, in_out); } } + + /* Remove leftover sockets that didn't match the node group's interface. */ + LISTBASE_FOREACH_MUTABLE (bNodeSocket *, unused_socket, &old_sockets) { + nodeRemoveSocket(&node_tree, &node, unused_socket); + } } -/* make sure all group node in ntree, which use ngroup, are sync'd */ void node_group_update(struct bNodeTree *ntree, struct bNode *node) { /* check inputs and outputs, and remove or insert them */ @@ -210,8 +212,8 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node) } else { bNodeTree *ngroup = (bNodeTree *)node->id; - group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN); - group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT); + group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN); + group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT); } } @@ -305,9 +307,6 @@ static void propagate_reroute_type_from_start_socket( } } -/* Global update function for Reroute node types. - * This depends on connected nodes, so must be done as a tree-wide update. - */ void ntree_update_reroute_nodes(bNodeTree *ntree) { /* Contains nodes that are linked to at least one reroute node. */ @@ -497,7 +496,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node) /* check inputs and outputs, and remove or insert them */ { /* value_in_out inverted for interface nodes to get correct socket value_property */ - group_verify_socket_list(ntree, node, &ntree->inputs, &node->outputs, SOCK_OUT); + group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT); /* add virtual extension socket */ nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", ""); @@ -595,7 +594,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node) /* check inputs and outputs, and remove or insert them */ { /* value_in_out inverted for interface nodes to get correct socket value_property */ - group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN); + group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN); /* add virtual extension socket */ nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", ""); @@ -613,6 +612,8 @@ void register_node_type_group_output(void) node_type_init(ntype, node_group_output_init); node_type_update(ntype, node_group_output_update); + ntype->no_muting = true; + nodeRegisterType(ntype); } diff --git a/source/blender/nodes/intern/node_common.h b/source/blender/nodes/intern/node_common.h index cdb7b6897b9..0d1b51224e6 100644 --- a/source/blender/nodes/intern/node_common.h +++ b/source/blender/nodes/intern/node_common.h @@ -31,11 +31,19 @@ extern "C" { struct bNodeTree; -void node_group_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); +/** Groups display their internal tree name as label. */ +void node_group_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); bool node_group_poll_instance(struct bNode *node, struct bNodeTree *nodetree, const char **r_disabled_hint); +/** + * Global update function for Reroute node types. + * This depends on connected nodes, so must be done as a tree-wide update. + */ void ntree_update_reroute_nodes(struct bNodeTree *ntree); #ifdef __cplusplus diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc index e804d10ad75..75d47cfd386 100644 --- a/source/blender/nodes/intern/node_declaration.cc +++ b/source/blender/nodes/intern/node_declaration.cc @@ -51,11 +51,14 @@ bNodeSocket &SocketDeclaration::update_or_build(bNodeTree &ntree, bNodeSocket &socket) const { /* By default just rebuild. */ - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + UNUSED_VARS_NDEBUG(socket); + return this->build(ntree, node); } void SocketDeclaration::set_common_flags(bNodeSocket &socket) const { + SET_FLAG_FROM_TEST(socket.flag, compact_, SOCK_COMPACT); SET_FLAG_FROM_TEST(socket.flag, hide_value_, SOCK_HIDE_VALUE); SET_FLAG_FROM_TEST(socket.flag, hide_label_, SOCK_HIDE_LABEL); SET_FLAG_FROM_TEST(socket.flag, is_multi_input_, SOCK_MULTI_INPUT); @@ -70,6 +73,9 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const if (socket.identifier != identifier_) { return false; } + if (((socket.flag & SOCK_COMPACT) != 0) != compact_) { + return false; + } if (((socket.flag & SOCK_HIDE_VALUE) != 0) != hide_value_) { return false; } diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc index 18403417af3..95070bf735e 100644 --- a/source/blender/nodes/intern/node_exec.cc +++ b/source/blender/nodes/intern/node_exec.cc @@ -34,14 +34,12 @@ #include "node_exec.h" #include "node_util.h" -/* supported socket types in old nodes */ int node_exec_socket_use_stack(bNodeSocket *sock) { /* NOTE: INT supported as FLOAT. Only for EEVEE. */ return ELEM(sock->type, SOCK_INT, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER); } -/* for a given socket, find the actual stack entry */ bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock) { if (stack && sock && sock->stack_index >= 0) { diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h index de7cbb8cedb..b2e1c6564b6 100644 --- a/source/blender/nodes/intern/node_exec.h +++ b/source/blender/nodes/intern/node_exec.h @@ -71,8 +71,10 @@ typedef struct bNodeThreadStack { bool used; } bNodeThreadStack; +/** Supported socket types in old nodes. */ int node_exec_socket_use_stack(struct bNodeSocket *sock); +/** For a given socket, find the actual stack entry. */ struct bNodeStack *node_get_socket_stack(struct bNodeStack *stack, struct bNodeSocket *sock); void node_get_stack(struct bNode *node, struct bNodeStack *stack, diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index faa4337ba7e..b5c4e71df74 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -18,8 +18,9 @@ #include "DEG_depsgraph_query.h" +#include "BKE_type_conversions.hh" + #include "NOD_geometry_exec.hh" -#include "NOD_type_conversions.hh" #include "node_geometry_util.hh" @@ -149,7 +150,7 @@ GVArray GeoNodeExecParams::get_input_attribute(const StringRef name, } return GVArray::ForSingle(*cpp_type, domain_size, default_value); } - const DataTypeConversions &conversions = get_implicit_type_conversions(); + const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); if (found_socket->type == SOCK_FLOAT) { const float value = this->get_input<float>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); @@ -215,11 +216,6 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type( return default_type; } -/** - * If any of the corresponding input sockets are attributes instead of single values, - * use the highest priority attribute domain from among them. - * Otherwise return the default domain. - */ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain( Span<std::string> names, const GeometryComponent &component, @@ -254,6 +250,11 @@ std::string GeoNodeExecParams::attribute_producer_name() const return provider_->dnode->label_or_name() + TIP_(" node"); } +void GeoNodeExecParams::set_default_remaining_outputs() +{ + provider_->set_default_remaining_outputs(); +} + void GeoNodeExecParams::check_input_access(StringRef identifier, const CPPType *requested_type) const { @@ -288,7 +289,7 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, BLI_assert_unreachable(); } else if (requested_type != nullptr) { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (*requested_type != expected_type) { std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; @@ -328,7 +329,7 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType BLI_assert_unreachable(); } else { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (value_type != expected_type) { std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index dce54d58dce..d83c05b38a1 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -28,7 +28,6 @@ #include "BLI_color.hh" #include "BLI_float3.hh" #include "BLI_listbase.h" -#include "BLI_math.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -51,6 +50,7 @@ #include "FN_field.hh" using namespace blender; +using blender::fn::ValueOrField; using blender::nodes::SocketDeclarationPtr; struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, @@ -191,7 +191,6 @@ static void refresh_socket_list(bNodeTree &ntree, bNode &node, ListBase &sockets, Span<SocketDeclarationPtr> socket_decls, - const eNodeSocketInOut in_out, const bool do_id_user) { Vector<bNodeSocket *> old_sockets = sockets; @@ -210,7 +209,7 @@ static void refresh_socket_list(bNodeTree &ntree, bNodeSocket *new_socket = nullptr; if (old_socket_with_same_identifier == nullptr) { /* Create a completely new socket. */ - new_socket = &socket_decl->build(ntree, node, in_out); + new_socket = &socket_decl->build(ntree, node); } else { STRNCPY(old_socket_with_same_identifier->name, socket_decl->name().c_str()); @@ -258,8 +257,8 @@ static void refresh_node(bNodeTree &ntree, blender::nodes::NodeDeclaration &node_decl, bool do_id_user) { - refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), SOCK_IN, do_id_user); - refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), SOCK_OUT, do_id_user); + refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), do_id_user); + refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), do_id_user); } void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user) @@ -548,7 +547,7 @@ void node_socket_skip_reroutes( } static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree), - bNodeSocket *stemp, + const bNodeSocket *interface_socket, bNode *UNUSED(node), bNodeSocket *sock, const char *UNUSED(data_path)) @@ -559,47 +558,50 @@ static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree), /* XXX socket interface 'type' value is not used really, * but has to match or the copy function will bail out */ - stemp->type = stemp->typeinfo->type; + const_cast<bNodeSocket *>(interface_socket)->type = interface_socket->typeinfo->type; /* copy default_value settings */ - node_socket_copy_default_value(sock, stemp); + node_socket_copy_default_value(sock, interface_socket); } /* copies settings that are not changed for each socket instance */ static void standard_node_socket_interface_verify_socket(bNodeTree *UNUSED(ntree), - bNodeSocket *stemp, + const bNodeSocket *interface_socket, bNode *UNUSED(node), bNodeSocket *sock, const char *UNUSED(data_path)) { /* sanity check */ - if (sock->type != stemp->typeinfo->type) { + if (sock->type != interface_socket->typeinfo->type) { return; } /* make sure both exist */ - if (!stemp->default_value) { + if (!interface_socket->default_value) { return; } node_socket_init_default_value(sock); - switch (stemp->typeinfo->type) { + switch (interface_socket->typeinfo->type) { case SOCK_FLOAT: { bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)sock->default_value; - bNodeSocketValueFloat *fromval = (bNodeSocketValueFloat *)stemp->default_value; + const bNodeSocketValueFloat *fromval = (const bNodeSocketValueFloat *) + interface_socket->default_value; toval->min = fromval->min; toval->max = fromval->max; break; } case SOCK_INT: { bNodeSocketValueInt *toval = (bNodeSocketValueInt *)sock->default_value; - bNodeSocketValueInt *fromval = (bNodeSocketValueInt *)stemp->default_value; + const bNodeSocketValueInt *fromval = (const bNodeSocketValueInt *) + interface_socket->default_value; toval->min = fromval->min; toval->max = fromval->max; break; } case SOCK_VECTOR: { bNodeSocketValueVector *toval = (bNodeSocketValueVector *)sock->default_value; - bNodeSocketValueVector *fromval = (bNodeSocketValueVector *)stemp->default_value; + const bNodeSocketValueVector *fromval = (const bNodeSocketValueVector *) + interface_socket->default_value; toval->min = fromval->min; toval->max = fromval->max; break; @@ -697,17 +699,15 @@ static bNodeSocketType *make_socket_type_virtual() static bNodeSocketType *make_socket_type_bool() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<bool>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<bool>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { bool value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<bool>(value); }; return socktype; } @@ -715,17 +715,15 @@ static bNodeSocketType *make_socket_type_bool() static bNodeSocketType *make_socket_type_float(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<float>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<float>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<float>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { float value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float>(value); }; return socktype; } @@ -733,17 +731,15 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) static bNodeSocketType *make_socket_type_int(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<int>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<int>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<int>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { int value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<int>(value); }; return socktype; } @@ -751,17 +747,15 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::float3>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::float3 value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::float3>(value); }; return socktype; } @@ -769,20 +763,16 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) static bNodeSocketType *make_socket_type_rgba() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE); - socktype->get_base_cpp_type = []() { - return &blender::fn::CPPType::get<blender::ColorGeometry4f>(); - }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::ColorGeometry4f>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>(); - }; + socktype->geometry_nodes_cpp_type = + &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::ColorGeometry4f value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) - blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::ColorGeometry4f>(value); }; return socktype; } @@ -790,18 +780,16 @@ static bNodeSocketType *make_socket_type_rgba() static bNodeSocketType *make_socket_type_string() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<std::string>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value); }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<std::string>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { std::string value; value.~basic_string(); socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<std::string>(value); }; return socktype; } @@ -815,11 +803,11 @@ MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType) static bNodeSocketType *make_socket_type_object() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Object *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Object *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -827,11 +815,11 @@ static bNodeSocketType *make_socket_type_object() static bNodeSocketType *make_socket_type_geometry() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<GeometrySet>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<GeometrySet>(); socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) { new (r_value) GeometrySet(); }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -839,11 +827,11 @@ static bNodeSocketType *make_socket_type_geometry() static bNodeSocketType *make_socket_type_collection() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Collection *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Collection *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -851,11 +839,11 @@ static bNodeSocketType *make_socket_type_collection() static bNodeSocketType *make_socket_type_texture() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Tex *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Tex *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -863,11 +851,11 @@ static bNodeSocketType *make_socket_type_texture() static bNodeSocketType *make_socket_type_image() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Image *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Image *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -875,11 +863,11 @@ static bNodeSocketType *make_socket_type_image() static bNodeSocketType *make_socket_type_material() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Material *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Material *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc index ed5691ebf7f..4fef5b96e9f 100644 --- a/source/blender/nodes/intern/node_socket_declarations.cc +++ b/source/blender/nodes/intern/node_socket_declarations.cc @@ -23,6 +23,52 @@ namespace blender::nodes::decl { +/** + * \note This function only deals with declarations, not the field status of existing nodes. If the + * field status of existing nodes was stored on the sockets, an improvement would be to check the + * existing socket's current status instead of the declaration. + */ +static bool field_types_are_compatible(const SocketDeclaration &input, + const SocketDeclaration &output) +{ + if (output.output_field_dependency().field_type() == OutputSocketFieldType::FieldSource) { + if (input.input_field_type() == InputSocketFieldType::None) { + return false; + } + } + return true; +} + +static bool sockets_can_connect(const SocketDeclaration &socket_decl, + const bNodeSocket &other_socket) +{ + /* Input sockets cannot connect to input sockets, outputs cannot connect to outputs. */ + if (socket_decl.in_out() == other_socket.in_out) { + return false; + } + + if (other_socket.declaration) { + if (socket_decl.in_out() == SOCK_IN) { + if (!field_types_are_compatible(socket_decl, *other_socket.declaration)) { + return false; + } + } + else { + if (!field_types_are_compatible(*other_socket.declaration, socket_decl)) { + return false; + } + } + } + + return true; +} + +static bool basic_types_can_connect(const SocketDeclaration &UNUSED(socket_decl), + const bNodeSocket &other_socket) +{ + return ELEM(other_socket.type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA); +} + static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subtype) { const char *idname = nodeStaticSocketType(socket.type, new_subtype); @@ -35,10 +81,10 @@ static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subty /** \name #Float * \{ */ -bNodeSocket &Float::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Float::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value; value.min = soft_min_value_; @@ -68,10 +114,19 @@ bool Float::matches(const bNodeSocket &socket) const return true; } +bool Float::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const { if (socket.type != SOCK_FLOAT) { - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + return this->build(ntree, node); } if (socket.typeinfo->subtype != subtype_) { modify_subtype_except_for_storage(socket, subtype_); @@ -90,10 +145,10 @@ bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket & /** \name #Int * \{ */ -bNodeSocket &Int::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Int::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value; value.min = soft_min_value_; @@ -123,10 +178,19 @@ bool Int::matches(const bNodeSocket &socket) const return true; } +bool Int::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const { if (socket.type != SOCK_INT) { - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + return this->build(ntree, node); } if (socket.typeinfo->subtype != subtype_) { modify_subtype_except_for_storage(socket, subtype_); @@ -145,10 +209,10 @@ bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &so /** \name #Vector * \{ */ -bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value; copy_v3_v3(value.value, default_value_); @@ -171,10 +235,19 @@ bool Vector::matches(const bNodeSocket &socket) const return true; } +bool Vector::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const { if (socket.type != SOCK_VECTOR) { - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + return this->build(ntree, node); } if (socket.typeinfo->subtype != subtype_) { modify_subtype_except_for_storage(socket, subtype_); @@ -192,10 +265,10 @@ bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket /** \name #Bool * \{ */ -bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueBoolean &value = *(bNodeSocketValueBoolean *)socket.default_value; value.value = default_value_; @@ -213,16 +286,24 @@ bool Bool::matches(const bNodeSocket &socket) const return true; } +bool Bool::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name #Color * \{ */ -bNodeSocket &Color::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Color::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueRGBA &value = *(bNodeSocketValueRGBA *)socket.default_value; copy_v4_v4(value.value, default_value_); @@ -245,16 +326,24 @@ bool Color::matches(const bNodeSocket &socket) const return true; } +bool Color::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name #String * \{ */ -bNodeSocket &String::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &String::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str()); STRNCPY(((bNodeSocketValueString *)socket.default_value)->value, default_value_.c_str()); this->set_common_flags(socket); return socket; @@ -271,18 +360,21 @@ bool String::matches(const bNodeSocket &socket) const return true; } +bool String::can_connect(const bNodeSocket &socket) const +{ + return sockets_can_connect(*this, socket) && socket.type == SOCK_STRING; +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name #IDSocketDeclaration * \{ */ -bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, - bNode &node, - eNodeSocketInOut in_out) const +bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddSocket( - &ntree, &node, in_out, idname_, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, idname_, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); return socket; } @@ -298,12 +390,18 @@ bool IDSocketDeclaration::matches(const bNodeSocket &socket) const return true; } +bool IDSocketDeclaration::can_connect(const bNodeSocket &socket) const +{ + return sockets_can_connect(*this, socket) && STREQ(socket.idname, idname_); +} + bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const { if (StringRef(socket.idname) != idname_) { - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + return this->build(ntree, node); } this->set_common_flags(socket); return socket; @@ -315,10 +413,10 @@ bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree, /** \name #Geometry * \{ */ -bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddSocket( - &ntree, &node, in_out, "NodeSocketGeometry", identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, "NodeSocketGeometry", identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); return socket; } @@ -334,6 +432,11 @@ bool Geometry::matches(const bNodeSocket &socket) const return true; } +bool Geometry::can_connect(const bNodeSocket &socket) const +{ + return sockets_can_connect(*this, socket) && socket.type == SOCK_GEOMETRY; +} + Span<GeometryComponentType> Geometry::supported_types() const { return supported_types_; @@ -376,4 +479,41 @@ GeometryBuilder &GeometryBuilder::only_instances(bool value) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name #Shader + * \{ */ + +bNodeSocket &Shader::build(bNodeTree &ntree, bNode &node) const +{ + bNodeSocket &socket = *nodeAddSocket( + &ntree, &node, in_out_, "NodeSocketShader", identifier_.c_str(), name_.c_str()); + this->set_common_flags(socket); + return socket; +} + +bool Shader::matches(const bNodeSocket &socket) const +{ + if (!this->matches_common_data(socket)) { + return false; + } + if (socket.type != SOCK_SHADER) { + return false; + } + return true; +} + +bool Shader::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + /* Basic types can convert to shaders, but not the other way around. */ + if (in_out_ == SOCK_IN) { + return ELEM(socket.type, SOCK_VECTOR, SOCK_RGBA, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN); + } + return socket.type == SOCK_SHADER; +} + +/** \} */ + } // namespace blender::nodes::decl diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index 5481465aef6..912d5e5322c 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -262,7 +262,6 @@ void InputSocketRef::foreach_logical_origin( skipped_fn.call_safe(origin); skipped_fn.call_safe(mute_input); mute_input.foreach_logical_origin(origin_fn, skipped_fn, true, seen_sockets_stack); - break; } } } @@ -442,9 +441,6 @@ static bool has_link_cycles_recursive(const NodeRef &node, return false; } -/** - * \return True when there is a link cycle. Unavailable sockets are ignored. - */ bool NodeTreeRef::has_link_cycles() const { const int node_amount = nodes_by_id_.size(); @@ -571,10 +567,6 @@ static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direct } } -/** - * Sort nodes topologically from left to right or right to left. - * In the future the result if this could be cached on #NodeTreeRef. - */ NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const { ToposortResult result; diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index 231030030eb..7620c8fa1a8 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -190,7 +190,7 @@ void node_math_update(bNodeTree *ntree, bNode *node) /** \name Labels * \{ */ -void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_blend_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name); @@ -200,14 +200,14 @@ void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int ma BLI_strncpy(label, IFACE_(name), maxlen); } -void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_image_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { /* If there is no loaded image, return an empty string, * and let nodeLabel() fill in the proper type translation. */ BLI_strncpy(label, (node->id) ? node->id->name + 2 : "", maxlen); } -void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_math_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_node_math_items, node->custom1, &name); @@ -217,7 +217,10 @@ void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int max BLI_strncpy(label, IFACE_(name), maxlen); } -void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_vector_math_label(const bNodeTree *UNUSED(ntree), + const bNode *node, + char *label, + int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name); @@ -227,7 +230,7 @@ void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, BLI_strncpy(label, IFACE_(name), maxlen); } -void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_filter_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name); @@ -301,11 +304,6 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, return NULL; } -/** - * The idea behind this is: When a user connects an input to a socket that is - * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for - * the link that we try to overwrite and connect that previous link to the new socket. - */ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link) { bNodeSocket *socket = link->tosock; @@ -351,11 +349,11 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link) * `< 0`: never connect these types. * `>= 0`: priority of connection (higher values chosen first). */ -static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype to) +static int node_datatype_priority(const bNodeSocketType *from, const bNodeSocketType *to) { - switch (to) { + switch (to->type) { case SOCK_RGBA: - switch (from) { + switch (from->type) { case SOCK_RGBA: return 4; case SOCK_FLOAT: @@ -364,11 +362,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_BOOLEAN: return 1; - default: - return -1; } + return -1; case SOCK_VECTOR: - switch (from) { + switch (from->type) { case SOCK_VECTOR: return 4; case SOCK_FLOAT: @@ -377,11 +374,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_BOOLEAN: return 1; - default: - return -1; } + return -1; case SOCK_FLOAT: - switch (from) { + switch (from->type) { case SOCK_FLOAT: return 5; case SOCK_INT: @@ -392,11 +388,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_VECTOR: return 1; - default: - return -1; } + return -1; case SOCK_INT: - switch (from) { + switch (from->type) { case SOCK_INT: return 5; case SOCK_FLOAT: @@ -407,11 +402,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_VECTOR: return 1; - default: - return -1; } + return -1; case SOCK_BOOLEAN: - switch (from) { + switch (from->type) { case SOCK_BOOLEAN: return 5; case SOCK_INT: @@ -422,74 +416,17 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_VECTOR: return 1; - default: - return -1; - } - case SOCK_SHADER: - switch (from) { - case SOCK_SHADER: - return 1; - default: - return -1; } - case SOCK_STRING: - switch (from) { - case SOCK_STRING: - return 1; - default: - return -1; - } - case SOCK_OBJECT: { - switch (from) { - case SOCK_OBJECT: - return 1; - default: - return -1; - } - } - case SOCK_GEOMETRY: { - switch (from) { - case SOCK_GEOMETRY: - return 1; - default: - return -1; - } - } - case SOCK_COLLECTION: { - switch (from) { - case SOCK_COLLECTION: - return 1; - default: - return -1; - } - } - case SOCK_TEXTURE: { - switch (from) { - case SOCK_TEXTURE: - return 1; - default: - return -1; - } - } - case SOCK_IMAGE: { - switch (from) { - case SOCK_IMAGE: - return 1; - default: - return -1; - } - } - case SOCK_MATERIAL: { - switch (from) { - case SOCK_MATERIAL: - return 1; - default: - return -1; - } - } - default: return -1; } + + /* The rest of the socket types only allow an internal link if both the input and output socket + * have the same type. If the sockets are custom, we check the idname instead. */ + if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) { + return 1; + } + + return -1; } /* select a suitable input socket for an output */ @@ -505,7 +442,7 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) bool sel_is_linked = false; for (input = node->inputs.first, i = 0; input; input = input->next, i++) { - int priority = node_datatype_priority(input->type, output->type); + int priority = node_datatype_priority(input->typeinfo, output->typeinfo); bool is_linked = (input->link != NULL); bool preferred; diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index c064ef4ab36..d7da2303088 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -23,20 +23,6 @@ #pragma once -#include "DNA_listBase.h" - -#include "BLI_utildefines.h" - -#include "BKE_node.h" - -#include "MEM_guardedalloc.h" - -#include "NOD_socket.h" - -#include "GPU_material.h" /* For Shader muting GPU code... */ - -#include "RNA_access.h" - #ifdef __cplusplus extern "C" { #endif @@ -56,18 +42,18 @@ typedef struct bNodeExecData { /**** Storage Data ****/ -extern void node_free_curves(struct bNode *node); -extern void node_free_standard_storage(struct bNode *node); +void node_free_curves(struct bNode *node); +void node_free_standard_storage(struct bNode *node); -extern void node_copy_curves(struct bNodeTree *dest_ntree, - struct bNode *dest_node, - const struct bNode *src_node); -extern void node_copy_standard_storage(struct bNodeTree *dest_ntree, - struct bNode *dest_node, - const struct bNode *src_node); -extern void *node_initexec_curves(struct bNodeExecContext *context, - struct bNode *node, - bNodeInstanceKey key); +void node_copy_curves(struct bNodeTree *dest_ntree, + struct bNode *dest_node, + const struct bNode *src_node); +void node_copy_standard_storage(struct bNodeTree *dest_ntree, + struct bNode *dest_node, + const struct bNode *src_node); +void *node_initexec_curves(struct bNodeExecContext *context, + struct bNode *node, + bNodeInstanceKey key); /**** Updates ****/ void node_sock_label(struct bNodeSocket *sock, const char *name); @@ -75,13 +61,34 @@ void node_sock_label_clear(struct bNodeSocket *sock); void node_math_update(struct bNodeTree *ntree, struct bNode *node); /**** Labels ****/ -void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -void node_vector_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); +void node_blend_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); +void node_image_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); +void node_math_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); +void node_vector_math_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); +void node_filter_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); /*** Link Handling */ + +/** + * The idea behind this is: When a user connects an input to a socket that is + * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for + * the link that we try to overwrite and connect that previous link to the new socket. + */ void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); diff --git a/source/blender/nodes/intern/socket_search_link.cc b/source/blender/nodes/intern/socket_search_link.cc new file mode 100644 index 00000000000..8543efe7f9b --- /dev/null +++ b/source/blender/nodes/intern/socket_search_link.cc @@ -0,0 +1,199 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_set.hh" + +#include "BKE_node.h" + +#include "UI_interface.h" + +#include "NOD_node_declaration.hh" +#include "NOD_socket_search_link.hh" + +namespace blender::nodes { + +void GatherLinkSearchOpParams::add_item(std::string socket_name, + SocketLinkOperation::LinkSocketFn fn, + const int weight) +{ + + std::string name = std::string(node_type_.ui_name) + " " + UI_MENU_ARROW_SEP + socket_name; + + items_.append({std::move(name), std::move(fn), weight}); +} + +const bNodeSocket &GatherLinkSearchOpParams::other_socket() const +{ + return other_socket_; +} + +const bNodeTree &GatherLinkSearchOpParams::node_tree() const +{ + return node_tree_; +} + +const bNodeType &GatherLinkSearchOpParams::node_type() const +{ + return node_type_; +} + +eNodeSocketInOut GatherLinkSearchOpParams::in_out() const +{ + return other_socket_.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN; +} + +void LinkSearchOpParams::connect_available_socket(bNode &new_node, StringRef socket_name) +{ + const eNodeSocketInOut in_out = socket.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN; + bNodeSocket *new_node_socket = bke::node_find_enabled_socket(new_node, in_out, socket_name); + if (new_node_socket == nullptr) { + /* If the socket isn't found, some node's search gather functions probably aren't configured + * properly. It's likely enough that it's worth avoiding a crash in a release build though. */ + BLI_assert_unreachable(); + return; + } + nodeAddLink(&node_tree, &new_node, new_node_socket, &node, &socket); +} + +bNode &LinkSearchOpParams::add_node(StringRef idname) +{ + std::string idname_str = idname; + bNode *node = nodeAddNode(&C, &node_tree, idname_str.c_str()); + BLI_assert(node != nullptr); + added_nodes_.append(node); + return *node; +} + +bNode &LinkSearchOpParams::add_node(const bNodeType &node_type) +{ + return this->add_node(node_type.idname); +} + +void LinkSearchOpParams::update_and_connect_available_socket(bNode &new_node, + StringRef socket_name) +{ + if (new_node.typeinfo->updatefunc) { + new_node.typeinfo->updatefunc(&node_tree, &new_node); + } + this->connect_available_socket(new_node, socket_name); +} + +void search_link_ops_for_declarations(GatherLinkSearchOpParams ¶ms, + Span<SocketDeclarationPtr> declarations) +{ + const bNodeType &node_type = params.node_type(); + + const SocketDeclaration *main_socket = nullptr; + Vector<const SocketDeclaration *> connectable_sockets; + + Set<StringRef> socket_names; + for (const int i : declarations.index_range()) { + const SocketDeclaration &socket = *declarations[i]; + if (!socket_names.add(socket.name())) { + /* Don't add sockets with the same name to the search. Needed to support being called from + * #search_link_ops_for_basic_node, which should have "okay" behavior for nodes with + * duplicate socket names. */ + continue; + } + if (!socket.can_connect(params.other_socket())) { + continue; + } + if (socket.is_default_link_socket() || main_socket == nullptr) { + /* Either the first connectable or explicitly tagged socket is the main socket. */ + main_socket = &socket; + } + connectable_sockets.append(&socket); + } + for (const int i : connectable_sockets.index_range()) { + const SocketDeclaration &socket = *connectable_sockets[i]; + /* Give non-main sockets a lower weight so that they don't show up at the top of the search + * when they are not explicitly searched for. The -1 is used to make sure that the first socket + * has a smaller weight than zero so that it does not have the same weight as the main socket. + * Negative weights are used to avoid making the highest weight dependent on the number of + * sockets. */ + const int weight = (&socket == main_socket) ? 0 : -1 - i; + params.add_item( + socket.name(), + [&node_type, &socket](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + socket.make_available(node); + params.update_and_connect_available_socket(node, socket.name()); + }, + weight); + } +} + +static void search_link_ops_for_socket_templates(GatherLinkSearchOpParams ¶ms, + const bNodeSocketTemplate *templates, + const eNodeSocketInOut in_out) +{ + const bNodeType &node_type = params.node_type(); + const bNodeTreeType &node_tree_type = *params.node_tree().typeinfo; + + Set<StringRef> socket_names; + for (const bNodeSocketTemplate *socket_template = templates; socket_template->type != -1; + socket_template++) { + eNodeSocketDatatype from = (eNodeSocketDatatype)socket_template->type; + eNodeSocketDatatype to = (eNodeSocketDatatype)params.other_socket().type; + if (in_out == SOCK_IN) { + std::swap(from, to); + } + if (node_tree_type.validate_link && !node_tree_type.validate_link(from, to)) { + continue; + } + if (!socket_names.add(socket_template->name)) { + /* See comment in #search_link_ops_for_declarations. */ + continue; + } + + params.add_item( + socket_template->name, [socket_template, node_type, in_out](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + bNodeSocket *new_node_socket = bke::node_find_enabled_socket( + node, in_out, socket_template->name); + if (new_node_socket != nullptr) { + /* Rely on the way #nodeAddLink switches in/out if necessary. */ + nodeAddLink(¶ms.node_tree, ¶ms.node, ¶ms.socket, &node, new_node_socket); + } + }); + } +} + +void search_link_ops_for_basic_node(GatherLinkSearchOpParams ¶ms) +{ + const bNodeType &node_type = params.node_type(); + + if (node_type.declare) { + if (node_type.declaration_is_dynamic) { + /* Dynamic declarations (whatever they end up being) aren't supported + * by this function, but still avoid a crash in release builds. */ + BLI_assert_unreachable(); + return; + } + + const NodeDeclaration &declaration = *node_type.fixed_declaration; + + search_link_ops_for_declarations(params, declaration.sockets(params.in_out())); + } + else if (node_type.inputs && params.in_out() == SOCK_IN) { + search_link_ops_for_socket_templates(params, node_type.inputs, SOCK_IN); + } + else if (node_type.outputs && params.in_out() == SOCK_OUT) { + search_link_ops_for_socket_templates(params, node_type.outputs, SOCK_OUT); + } +} + +} // namespace blender::nodes diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc deleted file mode 100644 index b1611679ced..00000000000 --- a/source/blender/nodes/intern/type_conversions.cc +++ /dev/null @@ -1,347 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "NOD_type_conversions.hh" - -#include "FN_multi_function_builder.hh" - -#include "BLI_color.hh" -#include "BLI_float2.hh" -#include "BLI_float3.hh" - -namespace blender::nodes { - -using fn::MFDataType; - -template<typename From, typename To, To (*ConversionF)(const From &)> -static void add_implicit_conversion(DataTypeConversions &conversions) -{ - const CPPType &from_type = CPPType::get<From>(); - const CPPType &to_type = CPPType::get<To>(); - const std::string conversion_name = from_type.name() + " to " + to_type.name(); - - static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name, ConversionF}; - static auto convert_single_to_initialized = [](const void *src, void *dst) { - *(To *)dst = ConversionF(*(const From *)src); - }; - static auto convert_single_to_uninitialized = [](const void *src, void *dst) { - new (dst) To(ConversionF(*(const From *)src)); - }; - conversions.add(fn::MFDataType::ForSingle<From>(), - fn::MFDataType::ForSingle<To>(), - multi_function, - convert_single_to_initialized, - convert_single_to_uninitialized); -} - -static float2 float_to_float2(const float &a) -{ - return float2(a); -} -static float3 float_to_float3(const float &a) -{ - return float3(a); -} -static int32_t float_to_int(const float &a) -{ - return (int32_t)a; -} -static bool float_to_bool(const float &a) -{ - return a > 0.0f; -} -static ColorGeometry4f float_to_color(const float &a) -{ - return ColorGeometry4f(a, a, a, 1.0f); -} - -static float3 float2_to_float3(const float2 &a) -{ - return float3(a.x, a.y, 0.0f); -} -static float float2_to_float(const float2 &a) -{ - return (a.x + a.y) / 2.0f; -} -static int float2_to_int(const float2 &a) -{ - return (int32_t)((a.x + a.y) / 2.0f); -} -static bool float2_to_bool(const float2 &a) -{ - return !is_zero_v2(a); -} -static ColorGeometry4f float2_to_color(const float2 &a) -{ - return ColorGeometry4f(a.x, a.y, 0.0f, 1.0f); -} - -static bool float3_to_bool(const float3 &a) -{ - return !is_zero_v3(a); -} -static float float3_to_float(const float3 &a) -{ - return (a.x + a.y + a.z) / 3.0f; -} -static int float3_to_int(const float3 &a) -{ - return (int)((a.x + a.y + a.z) / 3.0f); -} -static float2 float3_to_float2(const float3 &a) -{ - return float2(a); -} -static ColorGeometry4f float3_to_color(const float3 &a) -{ - return ColorGeometry4f(a.x, a.y, a.z, 1.0f); -} - -static bool int_to_bool(const int32_t &a) -{ - return a > 0; -} -static float int_to_float(const int32_t &a) -{ - return (float)a; -} -static float2 int_to_float2(const int32_t &a) -{ - return float2((float)a); -} -static float3 int_to_float3(const int32_t &a) -{ - return float3((float)a); -} -static ColorGeometry4f int_to_color(const int32_t &a) -{ - return ColorGeometry4f((float)a, (float)a, (float)a, 1.0f); -} - -static float bool_to_float(const bool &a) -{ - return (bool)a; -} -static int32_t bool_to_int(const bool &a) -{ - return (int32_t)a; -} -static float2 bool_to_float2(const bool &a) -{ - return (a) ? float2(1.0f) : float2(0.0f); -} -static float3 bool_to_float3(const bool &a) -{ - return (a) ? float3(1.0f) : float3(0.0f); -} -static ColorGeometry4f bool_to_color(const bool &a) -{ - return (a) ? ColorGeometry4f(1.0f, 1.0f, 1.0f, 1.0f) : ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f); -} - -static bool color_to_bool(const ColorGeometry4f &a) -{ - return rgb_to_grayscale(a) > 0.0f; -} -static float color_to_float(const ColorGeometry4f &a) -{ - return rgb_to_grayscale(a); -} -static int32_t color_to_int(const ColorGeometry4f &a) -{ - return (int)rgb_to_grayscale(a); -} -static float2 color_to_float2(const ColorGeometry4f &a) -{ - return float2(a.r, a.g); -} -static float3 color_to_float3(const ColorGeometry4f &a) -{ - return float3(a.r, a.g, a.b); -} - -static DataTypeConversions create_implicit_conversions() -{ - DataTypeConversions conversions; - - add_implicit_conversion<float, float2, float_to_float2>(conversions); - add_implicit_conversion<float, float3, float_to_float3>(conversions); - add_implicit_conversion<float, int32_t, float_to_int>(conversions); - add_implicit_conversion<float, bool, float_to_bool>(conversions); - add_implicit_conversion<float, ColorGeometry4f, float_to_color>(conversions); - - add_implicit_conversion<float2, float3, float2_to_float3>(conversions); - add_implicit_conversion<float2, float, float2_to_float>(conversions); - add_implicit_conversion<float2, int32_t, float2_to_int>(conversions); - add_implicit_conversion<float2, bool, float2_to_bool>(conversions); - add_implicit_conversion<float2, ColorGeometry4f, float2_to_color>(conversions); - - add_implicit_conversion<float3, bool, float3_to_bool>(conversions); - add_implicit_conversion<float3, float, float3_to_float>(conversions); - add_implicit_conversion<float3, int32_t, float3_to_int>(conversions); - add_implicit_conversion<float3, float2, float3_to_float2>(conversions); - add_implicit_conversion<float3, ColorGeometry4f, float3_to_color>(conversions); - - add_implicit_conversion<int32_t, bool, int_to_bool>(conversions); - add_implicit_conversion<int32_t, float, int_to_float>(conversions); - add_implicit_conversion<int32_t, float2, int_to_float2>(conversions); - add_implicit_conversion<int32_t, float3, int_to_float3>(conversions); - add_implicit_conversion<int32_t, ColorGeometry4f, int_to_color>(conversions); - - add_implicit_conversion<bool, float, bool_to_float>(conversions); - add_implicit_conversion<bool, int32_t, bool_to_int>(conversions); - add_implicit_conversion<bool, float2, bool_to_float2>(conversions); - add_implicit_conversion<bool, float3, bool_to_float3>(conversions); - add_implicit_conversion<bool, ColorGeometry4f, bool_to_color>(conversions); - - add_implicit_conversion<ColorGeometry4f, bool, color_to_bool>(conversions); - add_implicit_conversion<ColorGeometry4f, float, color_to_float>(conversions); - add_implicit_conversion<ColorGeometry4f, int32_t, color_to_int>(conversions); - add_implicit_conversion<ColorGeometry4f, float2, color_to_float2>(conversions); - add_implicit_conversion<ColorGeometry4f, float3, color_to_float3>(conversions); - - return conversions; -} - -const DataTypeConversions &get_implicit_type_conversions() -{ - static const DataTypeConversions conversions = create_implicit_conversions(); - return conversions; -} - -void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, - const CPPType &to_type, - const void *from_value, - void *to_value) const -{ - if (from_type == to_type) { - from_type.copy_construct(from_value, to_value); - return; - } - - const ConversionFunctions *functions = this->get_conversion_functions( - MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type)); - BLI_assert(functions != nullptr); - - functions->convert_single_to_uninitialized(from_value, to_value); -} - -class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl { - private: - fn::GVArray varray_; - const CPPType &from_type_; - ConversionFunctions old_to_new_conversions_; - - public: - GVArray_For_ConvertedGVArray(fn::GVArray varray, - const CPPType &to_type, - const DataTypeConversions &conversions) - : fn::GVArrayImpl(to_type, varray.size()), - varray_(std::move(varray)), - from_type_(varray_.type()) - { - old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); - } - - private: - void get(const int64_t index, void *r_value) const override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_.get(index, buffer); - old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); - from_type_.destruct(buffer); - } - - void get_to_uninitialized(const int64_t index, void *r_value) const override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_.get(index, buffer); - old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); - from_type_.destruct(buffer); - } -}; - -class GVMutableArray_For_ConvertedGVMutableArray : public fn::GVMutableArrayImpl { - private: - fn::GVMutableArray varray_; - const CPPType &from_type_; - ConversionFunctions old_to_new_conversions_; - ConversionFunctions new_to_old_conversions_; - - public: - GVMutableArray_For_ConvertedGVMutableArray(fn::GVMutableArray varray, - const CPPType &to_type, - const DataTypeConversions &conversions) - : fn::GVMutableArrayImpl(to_type, varray.size()), - varray_(std::move(varray)), - from_type_(varray_.type()) - { - old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); - new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_); - } - - private: - void get(const int64_t index, void *r_value) const override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_.get(index, buffer); - old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); - from_type_.destruct(buffer); - } - - void get_to_uninitialized(const int64_t index, void *r_value) const override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_.get(index, buffer); - old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); - from_type_.destruct(buffer); - } - - void set_by_move(const int64_t index, void *value) override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - new_to_old_conversions_.convert_single_to_uninitialized(value, buffer); - varray_.set_by_relocate(index, buffer); - } -}; - -fn::GVArray DataTypeConversions::try_convert(fn::GVArray varray, const CPPType &to_type) const -{ - const CPPType &from_type = varray.type(); - if (from_type == to_type) { - return varray; - } - if (!this->is_convertible(from_type, to_type)) { - return {}; - } - return fn::GVArray::For<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); -} - -fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray, - const CPPType &to_type) const -{ - const CPPType &from_type = varray.type(); - if (from_type == to_type) { - return varray; - } - if (!this->is_convertible(from_type, to_type)) { - return {}; - } - return fn::GVMutableArray::For<GVMutableArray_For_ConvertedGVMutableArray>( - std::move(varray), to_type, *this); -} - -} // namespace blender::nodes |