diff options
Diffstat (limited to 'source/blender/nodes/intern')
-rw-r--r-- | source/blender/nodes/intern/derived_node_tree.cc | 50 | ||||
-rw-r--r-- | source/blender/nodes/intern/math_functions.cc | 2 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_common.c | 20 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_common.h | 4 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_exec.cc (renamed from source/blender/nodes/intern/node_exec.c) | 49 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_geometry_exec.cc | 101 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_socket.cc | 137 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_tree_multi_function.cc | 128 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_tree_ref.cc | 223 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_util.c | 125 | ||||
-rw-r--r-- | source/blender/nodes/intern/type_callbacks.cc | 3 | ||||
-rw-r--r-- | source/blender/nodes/intern/type_conversions.cc | 349 |
12 files changed, 828 insertions, 363 deletions
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index e4f8a0c5fda..9a3eb574bcd 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_); @@ -83,6 +84,16 @@ bool DerivedNodeTree::has_link_cycles() const return false; } +bool DerivedNodeTree::has_undefined_nodes_or_sockets() const +{ + for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { + if (tree_ref->has_undefined_nodes_or_sockets()) { + return true; + } + } + 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 { @@ -167,10 +178,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 +191,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 +211,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 +244,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/math_functions.cc b/source/blender/nodes/intern/math_functions.cc index fb34144abf6..aa23777b664 100644 --- a/source/blender/nodes/intern/math_functions.cc +++ b/source/blender/nodes/intern/math_functions.cc @@ -209,6 +209,8 @@ const FloatMathOperationInfo *get_float3_math_operation_info(const int operation RETURN_OPERATION_INFO("Refract", "vector_math_refract"); case NODE_VECTOR_MATH_FACEFORWARD: RETURN_OPERATION_INFO("Faceforward", "vector_math_faceforward"); + case NODE_VECTOR_MATH_MULTIPLY_ADD: + RETURN_OPERATION_INFO("Multiply Add", "vector_math_multiply_add"); } #undef RETURN_OPERATION_INFO diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index 0b1ab85c059..7fc9f664df0 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -79,12 +79,12 @@ void node_group_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int ma BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Data-Block"), maxlen); } -bool node_group_poll_instance(bNode *node, bNodeTree *nodetree) +bool node_group_poll_instance(bNode *node, bNodeTree *nodetree, const char **disabled_hint) { - if (node->typeinfo->poll(node->typeinfo, nodetree)) { + if (node->typeinfo->poll(node->typeinfo, nodetree, disabled_hint)) { bNodeTree *grouptree = (bNodeTree *)node->id; if (grouptree) { - return nodeGroupPoll(nodetree, grouptree); + return nodeGroupPoll(nodetree, grouptree, disabled_hint); } return true; /* without a linked node tree, group node is always ok */ @@ -93,25 +93,27 @@ bool node_group_poll_instance(bNode *node, bNodeTree *nodetree) return false; } -int nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree) +bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_disabled_hint) { bNode *node; - int valid = 1; + bool valid = true; /* unspecified node group, generally allowed * (if anything, should be avoided on operator level) */ if (grouptree == NULL) { - return 1; + return true; } if (nodetree == grouptree) { - return 0; + *r_disabled_hint = "Nesting a node group inside of itself is not allowed"; + return false; } for (node = grouptree->nodes.first; node; node = node->next) { - if (node->typeinfo->poll_instance && !node->typeinfo->poll_instance(node, nodetree)) { - valid = 0; + if (node->typeinfo->poll_instance && + !node->typeinfo->poll_instance(node, nodetree, r_disabled_hint)) { + valid = false; break; } } diff --git a/source/blender/nodes/intern/node_common.h b/source/blender/nodes/intern/node_common.h index 7aad6782640..cdb7b6897b9 100644 --- a/source/blender/nodes/intern/node_common.h +++ b/source/blender/nodes/intern/node_common.h @@ -32,7 +32,9 @@ extern "C" { struct bNodeTree; void node_group_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -bool node_group_poll_instance(struct bNode *node, struct bNodeTree *nodetree); +bool node_group_poll_instance(struct bNode *node, + struct bNodeTree *nodetree, + const char **r_disabled_hint); void ntree_update_reroute_nodes(struct bNodeTree *ntree); diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.cc index dd9d0b6796a..18403417af3 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.cc @@ -47,7 +47,7 @@ bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock) if (stack && sock && sock->stack_index >= 0) { return stack + sock->stack_index; } - return NULL; + return nullptr; } void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out) @@ -56,13 +56,13 @@ void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack /* build pointer stack */ if (in) { - for (sock = node->inputs.first; sock; sock = sock->next) { + for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) { *(in++) = node_get_socket_stack(stack, sock); } } if (out) { - for (sock = node->outputs.first; sock; sock = sock->next) { + for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { *(out++) = node_get_socket_stack(stack, sock); } } @@ -90,7 +90,7 @@ static void node_init_output_index(bNodeSocket *sock, int *index, ListBase *inte if (internal_links) { bNodeLink *link; /* copy the stack index from internally connected input to skip the node */ - for (link = internal_links->first; link; link = link->next) { + for (link = (bNodeLink *)internal_links->first; link; link = link->next) { if (link->tosock == sock) { sock->stack_index = link->fromsock->stack_index; /* set the link pointer to indicate that this socket @@ -128,7 +128,7 @@ static struct bNodeStack *setup_stack(bNodeStack *stack, { bNodeStack *ns = node_get_socket_stack(stack, sock); if (!ns) { - return NULL; + return nullptr; } /* don't mess with remote socket stacks, these are initialized by other nodes! */ @@ -166,7 +166,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, int index; bNode **nodelist; int totnodes, n; - /* XXX texnodes have threading issues with muting, have to disable it there ... */ + /* XXX: texture-nodes have threading issues with muting, have to disable it there. */ /* ensure all sock->link pointers and node levels are correct */ /* Using global main here is likely totally wrong, not sure what to do about that one though... @@ -178,7 +178,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, ntreeGetDependencyList(ntree, &nodelist, &totnodes); /* XXX could let callbacks do this for specialized data */ - exec = MEM_callocN(sizeof(bNodeTreeExec), "node tree execution data"); + exec = (bNodeTreeExec *)MEM_callocN(sizeof(bNodeTreeExec), "node tree execution data"); /* backpointer to node tree */ exec->nodetree = ntree; @@ -188,28 +188,29 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, node = nodelist[n]; /* init node socket stack indexes */ - for (sock = node->inputs.first; sock; sock = sock->next) { + for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) { node_init_input_index(sock, &index); } if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) { - for (sock = node->outputs.first; sock; sock = sock->next) { + for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { node_init_output_index(sock, &index, &node->internal_links); } } else { - for (sock = node->outputs.first; sock; sock = sock->next) { - node_init_output_index(sock, &index, NULL); + for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { + node_init_output_index(sock, &index, nullptr); } } } /* allocated exec data pointers for nodes */ exec->totnodes = totnodes; - exec->nodeexec = MEM_callocN(exec->totnodes * sizeof(bNodeExec), "node execution data"); + exec->nodeexec = (bNodeExec *)MEM_callocN(exec->totnodes * sizeof(bNodeExec), + "node execution data"); /* allocate data pointer for node stack */ exec->stacksize = index; - exec->stack = MEM_callocN(exec->stacksize * sizeof(bNodeStack), "bNodeStack"); + exec->stack = (bNodeStack *)MEM_callocN(exec->stacksize * sizeof(bNodeStack), "bNodeStack"); /* all non-const results are considered inputs */ for (n = 0; n < exec->stacksize; n++) { @@ -222,7 +223,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, nodeexec->free_exec_fn = node->typeinfo->free_exec_fn; /* tag inputs */ - for (sock = node->inputs.first; sock; sock = sock->next) { + for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) { /* disable the node if an input link is invalid */ if (sock->link && !(sock->link->flag & NODE_LINK_VALID)) { node->need_exec = 0; @@ -235,14 +236,14 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, } /* tag all outputs */ - for (sock = node->outputs.first; sock; sock = sock->next) { + for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { /* ns = */ setup_stack(exec->stack, ntree, node, sock); } nodekey = BKE_node_instance_key(parent_key, ntree, node); - nodeexec->data.preview = context->previews ? - BKE_node_instance_hash_lookup(context->previews, nodekey) : - NULL; + nodeexec->data.preview = context->previews ? (bNodePreview *)BKE_node_instance_hash_lookup( + context->previews, nodekey) : + nullptr; if (node->typeinfo->init_exec_fn) { nodeexec->data.data = node->typeinfo->init_exec_fn(context, node, nodekey); } @@ -284,7 +285,7 @@ bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread) ListBase *lb = &exec->threadstack[thread]; bNodeThreadStack *nts; - for (nts = lb->first; nts; nts = nts->next) { + for (nts = (bNodeThreadStack *)lb->first; nts; nts = nts->next) { if (!nts->used) { nts->used = true; break; @@ -292,8 +293,8 @@ bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread) } if (!nts) { - nts = MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack"); - nts->stack = MEM_dupallocN(exec->stack); + nts = (bNodeThreadStack *)MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack"); + nts->stack = (bNodeStack *)MEM_dupallocN(exec->stack); nts->used = true; BLI_addtail(lb, nts); } @@ -303,13 +304,13 @@ bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread) void ntreeReleaseThreadStack(bNodeThreadStack *nts) { - nts->used = 0; + nts->used = false; } bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *callerdata, int thread) { - bNodeStack *nsin[MAX_SOCKET] = {NULL}; /* arbitrary... watch this */ - bNodeStack *nsout[MAX_SOCKET] = {NULL}; /* arbitrary... watch this */ + bNodeStack *nsin[MAX_SOCKET] = {nullptr}; /* arbitrary... watch this */ + bNodeStack *nsout[MAX_SOCKET] = {nullptr}; /* arbitrary... watch this */ bNodeExec *nodeexec; bNode *node; int n; diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index a4fb99a988e..188d198e159 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -22,6 +22,7 @@ #include "NOD_geometry_exec.hh" #include "NOD_type_callbacks.hh" +#include "NOD_type_conversions.hh" #include "node_geometry_util.hh" @@ -29,22 +30,22 @@ namespace blender::nodes { void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const { - bNodeTree *btree_cow = node_->btree(); + bNodeTree *btree_cow = provider_->dnode->btree(); BLI_assert(btree_cow != nullptr); if (btree_cow == nullptr) { return; } bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); - const NodeTreeEvaluationContext context(*self_object_, *modifier_); + const NodeTreeEvaluationContext context(*provider_->self_object, *provider_->modifier); BKE_nodetree_error_message_add( - *btree_original, context, *node_->bnode(), type, std::move(message)); + *btree_original, context, *provider_->dnode->bnode(), type, std::move(message)); } const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const { - for (const InputSocketRef *socket : node_->inputs()) { + for (const InputSocketRef *socket : provider_->dnode->inputs()) { if (socket->is_available() && socket->name() == name) { return socket->bsocket(); } @@ -53,22 +54,29 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name return nullptr; } -ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const +GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const { const bNodeSocket *found_socket = this->find_available_socket(name); BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */ + const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type); + const int64_t domain_size = component.attribute_domain_size(domain); + + if (default_value == nullptr) { + default_value = cpp_type->default_value(); + } + if (found_socket == nullptr) { - return component.attribute_get_constant_for_read(domain, type, default_value); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); } if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input<std::string>(found_socket->identifier); /* Try getting the attribute without the default value. */ - ReadAttributePtr attribute = component.attribute_try_get_for_read(name, domain, type); + GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, type); if (attribute) { return attribute; } @@ -80,25 +88,30 @@ ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name, this->error_message_add(NodeWarningType::Error, TIP_("No attribute with name \"") + name + "\""); } - return component.attribute_get_constant_for_read(domain, type, default_value); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); } + const DataTypeConversions &conversions = get_implicit_type_conversions(); if (found_socket->type == SOCK_FLOAT) { const float value = this->get_input<float>(found_socket->identifier); - return component.attribute_get_constant_for_read_converted( - domain, CD_PROP_FLOAT, type, &value); + BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); + conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_VECTOR) { const float3 value = this->get_input<float3>(found_socket->identifier); - return component.attribute_get_constant_for_read_converted( - domain, CD_PROP_FLOAT3, type, &value); + BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); + conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_RGBA) { - const Color4f value = this->get_input<Color4f>(found_socket->identifier); - return component.attribute_get_constant_for_read_converted( - domain, CD_PROP_COLOR, type, &value); + const ColorGeometry4f value = this->get_input<ColorGeometry4f>(found_socket->identifier); + BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); + conversions.convert_to_uninitialized( + CPPType::get<ColorGeometry4f>(), *cpp_type, &value, buffer); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); } BLI_assert(false); - return component.attribute_get_constant_for_read(domain, type, default_value); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); } CustomDataType GeoNodeExecParams::get_input_attribute_data_type( @@ -114,11 +127,11 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type( if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input<std::string>(found_socket->identifier); - ReadAttributePtr attribute = component.attribute_try_get_for_read(name); - if (!attribute) { - return default_type; + std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name); + if (info) { + return info->data_type; } - return attribute->custom_data_type(); + return default_type; } if (found_socket->type == SOCK_FLOAT) { return CD_PROP_FLOAT; @@ -157,9 +170,9 @@ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain( if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input<std::string>(found_socket->identifier); - ReadAttributePtr attribute = component.attribute_try_get_for_read(name); - if (attribute) { - input_domains.append(attribute->domain()); + std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name); + if (info) { + input_domains.append(info->domain); } } } @@ -171,11 +184,11 @@ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain( return default_domain; } -void GeoNodeExecParams::check_extract_input(StringRef identifier, - const CPPType *requested_type) const +void GeoNodeExecParams::check_input_access(StringRef identifier, + const CPPType *requested_type) const { bNodeSocket *found_socket = nullptr; - for (const InputSocketRef *socket : node_->inputs()) { + for (const InputSocketRef *socket : provider_->dnode->inputs()) { if (socket->identifier() == identifier) { found_socket = socket->bsocket(); break; @@ -185,39 +198,39 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, if (found_socket == nullptr) { std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const InputSocketRef *socket : node_->inputs()) { + for (const InputSocketRef *socket : provider_->dnode->inputs()) { if (socket->is_available()) { std::cout << "'" << socket->identifier() << "', "; } } std::cout << "\n"; - BLI_assert(false); + BLI_assert_unreachable(); } else if (found_socket->flag & SOCK_UNAVAIL) { std::cout << "The socket corresponding to the identifier '" << identifier << "' is disabled.\n"; - BLI_assert(false); + BLI_assert_unreachable(); } - else if (!input_values_.contains(identifier)) { + else if (!provider_->can_get_input(identifier)) { std::cout << "The identifier '" << identifier << "' is valid, but there is no value for it anymore.\n"; std::cout << "Most likely it has been extracted before.\n"; - BLI_assert(false); + BLI_assert_unreachable(); } else if (requested_type != nullptr) { const CPPType &expected_type = *socket_cpp_type_get(*found_socket->typeinfo); if (*requested_type != expected_type) { std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; - BLI_assert(false); + BLI_assert_unreachable(); } } } -void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &value_type) const +void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType &value_type) const { bNodeSocket *found_socket = nullptr; - for (const OutputSocketRef *socket : node_->outputs()) { + for (const OutputSocketRef *socket : provider_->dnode->outputs()) { if (socket->identifier() == identifier) { found_socket = socket->bsocket(); break; @@ -227,29 +240,29 @@ void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &va if (found_socket == nullptr) { std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const OutputSocketRef *socket : node_->outputs()) { + for (const OutputSocketRef *socket : provider_->dnode->outputs()) { if (socket->is_available()) { std::cout << "'" << socket->identifier() << "', "; } } std::cout << "\n"; - BLI_assert(false); + BLI_assert_unreachable(); } else if (found_socket->flag & SOCK_UNAVAIL) { std::cout << "The socket corresponding to the identifier '" << identifier << "' is disabled.\n"; - BLI_assert(false); + BLI_assert_unreachable(); } - else if (output_values_.contains(identifier)) { + else if (!provider_->can_set_output(identifier)) { std::cout << "The identifier '" << identifier << "' has been set already.\n"; - BLI_assert(false); + BLI_assert_unreachable(); } else { const CPPType &expected_type = *socket_cpp_type_get(*found_socket->typeinfo); if (value_type != expected_type) { std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; - BLI_assert(false); + BLI_assert_unreachable(); } } } diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 26df3f77738..d00bf636e15 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -35,9 +35,9 @@ #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" #include "BKE_node.h" -#include "BKE_persistent_data_handle.hh" #include "DNA_collection_types.h" +#include "DNA_material_types.h" #include "RNA_access.h" #include "RNA_types.h" @@ -52,7 +52,7 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, - int in_out) + eNodeSocketInOut in_out) { bNodeSocket *sock = nodeAddStaticSocket( ntree, node, in_out, stemp->type, stemp->subtype, stemp->identifier, stemp->name); @@ -102,8 +102,11 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, return sock; } -static bNodeSocket *verify_socket_template( - bNodeTree *ntree, bNode *node, int in_out, ListBase *socklist, bNodeSocketTemplate *stemp) +static bNodeSocket *verify_socket_template(bNodeTree *ntree, + bNode *node, + eNodeSocketInOut in_out, + ListBase *socklist, + bNodeSocketTemplate *stemp) { bNodeSocket *sock; @@ -132,7 +135,7 @@ static bNodeSocket *verify_socket_template( static void verify_socket_template_list(bNodeTree *ntree, bNode *node, - int in_out, + eNodeSocketInOut in_out, ListBase *socklist, bNodeSocketTemplate *stemp_first) { @@ -291,6 +294,21 @@ void node_socket_init_default_value(bNodeSocket *sock) sock->default_value = dval; break; + } + case SOCK_TEXTURE: { + bNodeSocketValueTexture *dval = (bNodeSocketValueTexture *)MEM_callocN( + sizeof(bNodeSocketValueTexture), "node socket value texture"); + dval->value = nullptr; + + sock->default_value = dval; + break; + } + case SOCK_MATERIAL: { + bNodeSocketValueMaterial *dval = (bNodeSocketValueMaterial *)MEM_callocN( + sizeof(bNodeSocketValueMaterial), "node socket value material"); + dval->value = nullptr; + + sock->default_value = dval; break; } } @@ -372,6 +390,20 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from) id_us_plus(&toval->value->id); break; } + case SOCK_TEXTURE: { + bNodeSocketValueTexture *toval = (bNodeSocketValueTexture *)to->default_value; + bNodeSocketValueTexture *fromval = (bNodeSocketValueTexture *)from->default_value; + *toval = *fromval; + id_us_plus(&toval->value->id); + break; + } + case SOCK_MATERIAL: { + bNodeSocketValueMaterial *toval = (bNodeSocketValueMaterial *)to->default_value; + bNodeSocketValueMaterial *fromval = (bNodeSocketValueMaterial *)from->default_value; + *toval = *fromval; + id_us_plus(&toval->value->id); + break; + } } to->flag |= (from->flag & SOCK_HIDE_VALUE); @@ -613,9 +645,9 @@ 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_cpp_type = []() { return &blender::fn::CPPType::get<blender::Color4f>(); }; + socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<blender::ColorGeometry4f>(); }; socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) { - *(blender::Color4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; + *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; return socktype; } @@ -630,63 +662,17 @@ static bNodeSocketType *make_socket_type_string() return socktype; } -class ObjectSocketMultiFunction : public blender::fn::MultiFunction { - private: - Object *object_; - - public: - ObjectSocketMultiFunction(Object *object) : object_(object) - { - static blender::fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static blender::fn::MFSignature create_signature() - { - blender::fn::MFSignatureBuilder signature{"Object Socket"}; - signature.depends_on_context(); - signature.single_output<blender::bke::PersistentObjectHandle>("Object"); - return signature.build(); - } - - void call(blender::IndexMask mask, - blender::fn::MFParams params, - blender::fn::MFContext context) const override - { - blender::MutableSpan output = - params.uninitialized_single_output<blender::bke::PersistentObjectHandle>(0, "Object"); - - /* Try to get a handle map, so that the object can be converted to a handle. */ - const blender::bke::PersistentDataHandleMap *handle_map = - context.get_global_context<blender::bke::PersistentDataHandleMap>( - "PersistentDataHandleMap"); - - if (handle_map == nullptr) { - /* Return empty handles when there is no handle map. */ - output.fill_indices(mask, blender::bke::PersistentObjectHandle()); - return; - } - - blender::bke::PersistentObjectHandle handle = handle_map->lookup(object_); - for (int64_t i : mask) { - output[i] = handle; - } - } -}; - -MAKE_CPP_TYPE(PersistentObjectHandle, blender::bke::PersistentObjectHandle); -MAKE_CPP_TYPE(PersistentCollectionHandle, blender::bke::PersistentCollectionHandle); +MAKE_CPP_TYPE(Object, Object *) +MAKE_CPP_TYPE(Collection, Collection *) +MAKE_CPP_TYPE(Texture, Tex *) +MAKE_CPP_TYPE(Material, Material *) static bNodeSocketType *make_socket_type_object() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE); - socktype->get_cpp_type = []() { - /* Objects are not passed along as raw pointers, but as handles. */ - return &blender::fn::CPPType::get<blender::bke::PersistentObjectHandle>(); - }; - socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) { - Object *object = builder.socket_default_value<bNodeSocketValueObject>()->value; - builder.construct_generator_fn<ObjectSocketMultiFunction>(object); + socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<Object *>(); }; + socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) { + *(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value; }; return socktype; } @@ -704,9 +690,29 @@ static bNodeSocketType *make_socket_type_geometry() static bNodeSocketType *make_socket_type_collection() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE); - socktype->get_cpp_type = []() { - /* Objects are not passed along as raw pointers, but as handles. */ - return &blender::fn::CPPType::get<blender::bke::PersistentCollectionHandle>(); + socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<Collection *>(); }; + socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) { + *(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value; + }; + return socktype; +} + +static bNodeSocketType *make_socket_type_texture() +{ + bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE); + socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<Tex *>(); }; + socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) { + *(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value; + }; + return socktype; +} + +static bNodeSocketType *make_socket_type_material() +{ + bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE); + socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<Material *>(); }; + socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) { + *(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value; }; return socktype; } @@ -721,6 +727,7 @@ void register_standard_node_socket_types(void) nodeRegisterSocketType(make_socket_type_float(PROP_FACTOR)); nodeRegisterSocketType(make_socket_type_float(PROP_ANGLE)); nodeRegisterSocketType(make_socket_type_float(PROP_TIME)); + nodeRegisterSocketType(make_socket_type_float(PROP_TIME_ABSOLUTE)); nodeRegisterSocketType(make_socket_type_float(PROP_DISTANCE)); nodeRegisterSocketType(make_socket_type_int(PROP_NONE)); @@ -752,5 +759,9 @@ void register_standard_node_socket_types(void) nodeRegisterSocketType(make_socket_type_collection()); + nodeRegisterSocketType(make_socket_type_texture()); + + nodeRegisterSocketType(make_socket_type_material()); + nodeRegisterSocketType(make_socket_type_virtual()); } diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index b973350becd..7ab6495f733 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -15,6 +15,7 @@ */ #include "NOD_node_tree_multi_function.hh" +#include "NOD_type_conversions.hh" #include "FN_multi_function_network_evaluation.hh" @@ -142,118 +143,16 @@ static void insert_nodes(CommonMFNetworkBuilderData &common) }); } -template<typename From, typename To> -static void add_implicit_conversion(DataTypeConversions &conversions) -{ - static fn::CustomMF_Convert<From, To> function; - conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), function); -} - -template<typename From, typename To, typename ConversionF> -static void add_implicit_conversion(DataTypeConversions &conversions, - StringRef name, - ConversionF conversion) -{ - static fn::CustomMF_SI_SO<From, To> function{name, conversion}; - conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), function); -} - -static DataTypeConversions create_implicit_conversions() -{ - DataTypeConversions conversions; - add_implicit_conversion<float, float2>(conversions); - add_implicit_conversion<float, float3>(conversions); - add_implicit_conversion<float, int32_t>(conversions); - add_implicit_conversion<float, bool>(conversions); - add_implicit_conversion<float, Color4f>( - conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); }); - - add_implicit_conversion<float2, float3>( - conversions, "float2 to float3", [](float2 a) { return float3(a.x, a.y, 0.0f); }); - add_implicit_conversion<float2, float>( - conversions, "float2 to float", [](float2 a) { return (a.x + a.y) / 2.0f; }); - add_implicit_conversion<float2, int32_t>( - conversions, "float2 to int32_t", [](float2 a) { return (int32_t)((a.x + a.y) / 2.0f); }); - add_implicit_conversion<float2, bool>( - conversions, "float2 to bool", [](float2 a) { return !is_zero_v2(a); }); - add_implicit_conversion<float2, Color4f>( - conversions, "float2 to Color4f", [](float2 a) { return Color4f(a.x, a.y, 0.0f, 1.0f); }); - - add_implicit_conversion<float3, bool>( - conversions, "float3 to boolean", [](float3 a) { return !is_zero_v3(a); }); - add_implicit_conversion<float3, float>( - conversions, "float3 to float", [](float3 a) { return (a.x + a.y + a.z) / 3.0f; }); - add_implicit_conversion<float3, int32_t>( - conversions, "float3 to int32_t", [](float3 a) { return (int)((a.x + a.y + a.z) / 3.0f); }); - add_implicit_conversion<float3, float2>(conversions); - add_implicit_conversion<float3, Color4f>( - conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); }); - - add_implicit_conversion<int32_t, bool>(conversions); - add_implicit_conversion<int32_t, float>(conversions); - add_implicit_conversion<int32_t, float2>( - conversions, "int32 to float2", [](int32_t a) { return float2((float)a); }); - add_implicit_conversion<int32_t, float3>( - conversions, "int32 to float3", [](int32_t a) { return float3((float)a); }); - add_implicit_conversion<int32_t, Color4f>(conversions, "int32 to Color4f", [](int32_t a) { - return Color4f((float)a, (float)a, (float)a, 1.0f); - }); - - add_implicit_conversion<bool, float>(conversions); - add_implicit_conversion<bool, int32_t>(conversions); - add_implicit_conversion<bool, float2>( - conversions, "boolean to float2", [](bool a) { return (a) ? float2(1.0f) : float2(0.0f); }); - add_implicit_conversion<bool, float3>( - conversions, "boolean to float3", [](bool a) { return (a) ? float3(1.0f) : float3(0.0f); }); - add_implicit_conversion<bool, Color4f>(conversions, "boolean to Color4f", [](bool a) { - return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f); - }); - - add_implicit_conversion<Color4f, bool>(conversions, "Color4f to boolean", [](Color4f a) { - return a.r != 0.0f && a.g != 0.0f && a.b != 0.0f; - }); - add_implicit_conversion<Color4f, float>( - conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); }); - add_implicit_conversion<Color4f, float2>( - conversions, "Color4f to float2", [](Color4f a) { return float2(a.r, a.g); }); - add_implicit_conversion<Color4f, float3>( - conversions, "Color4f to float3", [](Color4f a) { return float3(a.r, a.g, a.b); }); - - return conversions; -} - -const DataTypeConversions &get_implicit_type_conversions() -{ - static const DataTypeConversions conversions = create_implicit_conversions(); - return conversions; -} - -void DataTypeConversions::convert(const CPPType &from_type, - const CPPType &to_type, - const void *from_value, - void *to_value) const -{ - const fn::MultiFunction *fn = this->get_conversion(MFDataType::ForSingle(from_type), - MFDataType::ForSingle(to_type)); - BLI_assert(fn != nullptr); - - fn::MFContextBuilder context; - fn::MFParamsBuilder params{*fn, 1}; - params.add_readonly_single_input(fn::GSpan(from_type, from_value, 1)); - params.add_uninitialized_single_output(fn::GMutableSpan(to_type, to_value, 1)); - fn->call({0}, params, context); -} - static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderData &common, fn::MFDataType type) { const fn::MultiFunction *default_fn; if (type.is_single()) { - default_fn = &common.resources.construct<fn::CustomMF_GenericConstant>( + default_fn = &common.scope.construct<fn::CustomMF_GenericConstant>( AT, type.single_type(), type.single_type().default_value()); } else { - default_fn = &common.resources.construct<fn::CustomMF_GenericConstantArray>( + default_fn = &common.scope.construct<fn::CustomMF_GenericConstantArray>( AT, fn::GSpan(type.vector_base_type())); } @@ -320,8 +219,8 @@ static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common) const fn::MFDataType from_type = from_socket->data_type(); if (from_type != to_type) { - const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion( - from_type, to_type); + const fn::MultiFunction *conversion_fn = + get_implicit_type_conversions().get_conversion_multi_function(from_type, to_type); if (conversion_fn != nullptr) { fn::MFNode &node = common.network.add_function(*conversion_fn); common.network.add_link(*from_socket, node.input(0)); @@ -348,11 +247,11 @@ static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common) */ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, const DerivedNodeTree &tree, - ResourceCollector &resources) + ResourceScope &scope) { MFNetworkTreeMap network_map{tree, network}; - CommonMFNetworkBuilderData common{resources, network, network_map, tree}; + CommonMFNetworkBuilderData common{scope, network, network_map, tree}; insert_nodes(common); insert_links_and_unlinked_inputs(common); @@ -426,7 +325,7 @@ static const fn::MultiFunction &create_function_for_node_that_expands_into_multi const DNode &dnode, fn::MFNetwork &network, MFNetworkTreeMap &network_map, - ResourceCollector &resources) + ResourceScope &scope) { Vector<const fn::MFOutputSocket *> dummy_fn_inputs; for (const InputSocketRef *dsocket : dnode->inputs()) { @@ -451,7 +350,7 @@ static const fn::MultiFunction &create_function_for_node_that_expands_into_multi } } - fn::MFNetworkEvaluator &fn_evaluator = resources.construct<fn::MFNetworkEvaluator>( + fn::MFNetworkEvaluator &fn_evaluator = scope.construct<fn::MFNetworkEvaluator>( __func__, std::move(dummy_fn_inputs), std::move(dummy_fn_outputs)); return fn_evaluator; } @@ -460,16 +359,15 @@ static const fn::MultiFunction &create_function_for_node_that_expands_into_multi * Returns a single multi-function for every node that supports it. This makes it easier to reuse * the multi-function implementation of nodes in different contexts. */ -MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, - ResourceCollector &resources) +MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, ResourceScope &scope) { /* Build a network that nodes can insert themselves into. However, the individual nodes are not * connected. */ - fn::MFNetwork &network = resources.construct<fn::MFNetwork>(__func__); + fn::MFNetwork &network = scope.construct<fn::MFNetwork>(__func__); MFNetworkTreeMap network_map{tree, network}; MultiFunctionByNode functions_by_node; - CommonMFNetworkBuilderData common{resources, network, network_map, tree}; + CommonMFNetworkBuilderData common{scope, network, network_map, tree}; tree.foreach_node([&](DNode dnode) { const bNodeType *node_type = dnode->typeinfo(); @@ -498,7 +396,7 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, /* If a node expanded into multiple functions, a new function has to be created that * combines those. */ const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple( - dnode, network, network_map, resources); + dnode, network, network_map, scope); functions_by_node.add_new(dnode, &fn); break; } diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index e627a7f4497..154ee716153 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -14,6 +14,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include <mutex> + #include "NOD_node_tree_ref.hh" #include "BLI_dot_export.hh" @@ -105,6 +107,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) } } + this->create_socket_identifier_maps(); this->create_linked_socket_caches(); for (NodeRef *node : nodes_by_id_) { @@ -163,7 +166,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 +174,14 @@ 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; + Vector<const InputSocketRef *> handled_sockets; + socket->foreach_logical_origin( + [&](const OutputSocketRef &origin) { logically_linked_sockets.append(&origin); }, + [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }, + false, + handled_sockets); if (logically_linked_sockets == directly_linked_sockets) { socket->logically_linked_sockets_ = socket->directly_linked_sockets_; } @@ -181,11 +189,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 +203,13 @@ 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; + Vector<const OutputSocketRef *> handled_sockets; + socket->foreach_logical_target( + [&](const InputSocketRef &target) { logically_linked_sockets.append(&target); }, + [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }, + handled_sockets); if (logically_linked_sockets == directly_linked_sockets) { socket->logically_linked_sockets_ = socket->directly_linked_sockets_; } @@ -203,61 +217,187 @@ 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, + Vector<const InputSocketRef *> &handled_sockets) const { - Span<LinkRef *> links_to_check = socket.directly_linked_links_; + /* Protect against loops. */ + if (handled_sockets.contains(this)) { + return; + } + handled_sockets.append(this); + + 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.is_available()) { + /* Non available sockets are ignored. */ } - 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_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, handled_sockets); + } + 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, handled_sockets); 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, + Vector<const OutputSocketRef *> &handled_sockets) const { - for (LinkRef *link : socket.directly_linked_links_) { + /* Protect against loops. */ + if (handled_sockets.contains(this)) { + return; + } + handled_sockets.append(this); + + 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.is_available()) { + /* Non available sockets are ignored. */ } - 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_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, handled_sockets); + } + 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) { + /* The internal link only forwards the first incoming link. */ + if (target.is_multi_input_socket()) { + if (target.directly_linked_links()[0] != link) { + continue; + } + } + 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, handled_sockets); } } } else { - callback(*target); + target_fn(target); + } + } +} + +namespace { +struct SocketByIdentifierMap { + SocketIndexByIdentifierMap *map = nullptr; + std::unique_ptr<SocketIndexByIdentifierMap> owned_map; +}; +} // namespace + +static std::unique_ptr<SocketIndexByIdentifierMap> create_identifier_map(const ListBase &sockets) +{ + std::unique_ptr<SocketIndexByIdentifierMap> map = std::make_unique<SocketIndexByIdentifierMap>(); + int index; + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sockets, index) { + map->add_new(socket->identifier, index); + } + return map; +} + +/* This function is not threadsafe. */ +static SocketByIdentifierMap get_or_create_identifier_map( + const bNode &node, const ListBase &sockets, const bNodeSocketTemplate *sockets_template) +{ + SocketByIdentifierMap map; + if (sockets_template == nullptr) { + if (BLI_listbase_is_empty(&sockets)) { + static SocketIndexByIdentifierMap empty_map; + map.map = &empty_map; + } + else if (node.type == NODE_REROUTE) { + if (&node.inputs == &sockets) { + static SocketIndexByIdentifierMap reroute_input_map = [] { + SocketIndexByIdentifierMap map; + map.add_new("Input", 0); + return map; + }(); + map.map = &reroute_input_map; + } + else { + static SocketIndexByIdentifierMap reroute_output_map = [] { + SocketIndexByIdentifierMap map; + map.add_new("Output", 0); + return map; + }(); + map.map = &reroute_output_map; + } + } + else { + /* The node has a dynamic amount of sockets. Therefore we need to create a new map. */ + map.owned_map = create_identifier_map(sockets); + map.map = &*map.owned_map; + } + } + else { + /* Cache only one map for nodes that have the same sockets. */ + static Map<const bNodeSocketTemplate *, std::unique_ptr<SocketIndexByIdentifierMap>> maps; + map.map = &*maps.lookup_or_add_cb(sockets_template, + [&]() { return create_identifier_map(sockets); }); + } + return map; +} + +void NodeTreeRef::create_socket_identifier_maps() +{ + /* `get_or_create_identifier_map` is not threadsafe, therefore we have to hold a lock here. */ + static std::mutex mutex; + std::lock_guard lock{mutex}; + + for (NodeRef *node : nodes_by_id_) { + bNode &bnode = *node->bnode_; + SocketByIdentifierMap inputs_map = get_or_create_identifier_map( + bnode, bnode.inputs, bnode.typeinfo->inputs); + SocketByIdentifierMap outputs_map = get_or_create_identifier_map( + bnode, bnode.outputs, bnode.typeinfo->outputs); + node->input_index_by_identifier_ = inputs_map.map; + node->output_index_by_identifier_ = outputs_map.map; + if (inputs_map.owned_map) { + owned_identifier_maps_.append(std::move(inputs_map.owned_map)); + } + if (outputs_map.owned_map) { + owned_identifier_maps_.append(std::move(outputs_map.owned_map)); } } } @@ -304,6 +444,21 @@ bool NodeTreeRef::has_link_cycles() const return false; } +bool NodeTreeRef::has_undefined_nodes_or_sockets() const +{ + for (const NodeRef *node : nodes_by_id_) { + if (node->is_undefined()) { + return true; + } + } + for (const SocketRef *socket : sockets_by_id_) { + if (socket->is_undefined()) { + return true; + } + } + return true; +} + std::string NodeTreeRef::to_dot() const { dot::DirectedGraph digraph; diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index 00db819721c..1aec280fd2b 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -140,8 +140,8 @@ void node_math_update(bNodeTree *UNUSED(ntree), bNode *node) switch (node->custom1) { case NODE_MATH_WRAP: - node_sock_label(sock2, "Min"); - node_sock_label(sock3, "Max"); + node_sock_label(sock2, "Max"); + node_sock_label(sock3, "Min"); break; case NODE_MATH_MULTIPLY_ADD: node_sock_label(sock2, "Multiplier"); @@ -239,24 +239,21 @@ void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int m /** \name Link Insertion * \{ */ -/* test if two sockets are interchangeable */ -static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b) +static bool node_link_socket_match(const bNodeSocket *a, const bNodeSocket *b) { - /* check if sockets are of the same type */ + /* Check if sockets are of the same type. */ if (a->typeinfo != b->typeinfo) { return false; } - /* tests if alphabetic prefix matches - * this allows for imperfect matches, such as numeric suffixes, - * like Color1/Color2 - */ + /* Test if alphabetic prefix matches, allowing for imperfect matches, such as numeric suffixes + * like Color1/Color2. */ int prefix_len = 0; - char *ca = a->name, *cb = b->name; + const char *ca = a->name, *cb = b->name; for (; *ca != '\0' && *cb != '\0'; ca++, cb++) { - /* end of common prefix? */ + /* End of common prefix? */ if (*ca != *cb) { - /* prefix delimited by non-alphabetic char */ + /* Prefix delimited by non-alphabetic char. */ if (isalpha(*ca) || isalpha(*cb)) { return false; } @@ -267,75 +264,73 @@ static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b) return prefix_len > 0; } -static int node_count_links(bNodeTree *ntree, bNodeSocket *sock) +static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket) { - bNodeLink *link; int count = 0; - for (link = ntree->links.first; link; link = link->next) { - if (link->fromsock == sock) { - count++; - } - if (link->tosock == sock) { + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { + if (ELEM(socket, link->fromsock, link->tosock)) { count++; } } return count; } -/* Find an eligible socket for linking. */ -static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur) +static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, + bNode *node, + bNodeSocket *to_socket) { - bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first; - bNodeSocket *sock; - - /* Iterate over all sockets of the target node, to find one that matches the same socket type. - * 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. */ - sock = cur->next ? cur->next : first; /* Wrap around the list end. */ - while (sock != cur) { - if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) { - break; + bNodeSocket *first = to_socket->in_out == SOCK_IN ? node->inputs.first : node->outputs.first; + + /* Wrap around the list end. */ + bNodeSocket *socket_iter = to_socket->next ? to_socket->next : first; + while (socket_iter != to_socket) { + if (!nodeSocketIsHidden(socket_iter) && node_link_socket_match(socket_iter, to_socket)) { + const int link_count = node_count_links(ntree, socket_iter); + /* Add one to account for the new link being added. */ + if (link_count + 1 <= nodeSocketLinkLimit(socket_iter)) { + return socket_iter; /* Found a valid free socket we can swap to. */ + } } - sock = sock->next ? sock->next : first; /* Wrap around the list end. */ + socket_iter = socket_iter->next ? socket_iter->next : first; /* Wrap around the list end. */ } - if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) { - int link_count = node_count_links(ntree, sock); - /* Take +1 into account since we would add a new link. */ - if (link_count + 1 <= nodeSocketLinkLimit(sock)) { - return sock; /* Found a valid free socket we can swap to. */ - } - } 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 *sock = link->tosock; - bNodeLink *tlink, *tlink_next; + bNodeSocket *socket = link->tosock; if (node != link->tonode) { return; } - for (tlink = ntree->links.first; tlink; tlink = tlink_next) { - bNodeSocket *new_sock; - tlink_next = tlink->next; + /* If we're not at the link limit of the target socket, we can skip + * trying to move existing links to another socket. */ + const int to_link_limit = nodeSocketLinkLimit(socket); + if (socket->total_inputs + 1 < to_link_limit) { + return; + } - if (sock != tlink->tosock) { - continue; - } + LISTBASE_FOREACH_MUTABLE (bNodeLink *, to_link, &ntree->links) { + if (socket == to_link->tosock) { + bNodeSocket *new_socket = node_find_linkable_socket(ntree, node, socket); + if (new_socket && new_socket != socket) { + /* Attempt to redirect the existing link to the new socket. */ + to_link->tosock = new_socket; + return; + } - new_sock = node_find_linkable_socket(ntree, node, sock); - if (new_sock && new_sock != sock) { - /* redirect existing link */ - tlink->tosock = new_sock; - } - else if (!new_sock) { - /* no possible replacement, remove tlink */ - nodeRemLink(ntree, tlink); - tlink = NULL; + if (new_socket == NULL) { + /* No possible replacement, remove the existing link. */ + nodeRemLink(ntree, to_link); + return; + } } } } @@ -464,6 +459,22 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return -1; } } + case SOCK_TEXTURE: { + switch (from) { + case SOCK_TEXTURE: + return 1; + default: + return -1; + } + } + case SOCK_MATERIAL: { + switch (from) { + case SOCK_MATERIAL: + return 1; + default: + return -1; + } + } default: return -1; } diff --git a/source/blender/nodes/intern/type_callbacks.cc b/source/blender/nodes/intern/type_callbacks.cc index 26eeaebc6d4..5160432aea5 100644 --- a/source/blender/nodes/intern/type_callbacks.cc +++ b/source/blender/nodes/intern/type_callbacks.cc @@ -64,7 +64,8 @@ void socket_expand_in_mf_network(SocketMFNetworkBuilder &builder) } else if (socket.typeinfo->get_cpp_value != nullptr) { const CPPType &type = *socket_cpp_type_get(*socket.typeinfo); - void *buffer = builder.resources().linear_allocator().allocate(type.size(), type.alignment()); + void *buffer = builder.resource_scope().linear_allocator().allocate(type.size(), + type.alignment()); socket.typeinfo->get_cpp_value(socket, buffer); builder.set_constant_value(type, buffer); } diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc new file mode 100644 index 00000000000..220e5ea9046 --- /dev/null +++ b/source/blender/nodes/intern/type_conversions.cc @@ -0,0 +1,349 @@ +/* + * 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::GVArrayPtr; +using fn::GVMutableArray; +using fn::GVMutableArrayPtr; +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_to_uninitialized(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 GVArray { + private: + GVArrayPtr varray_; + const CPPType &from_type_; + ConversionFunctions old_to_new_conversions_; + + public: + GVArray_For_ConvertedGVArray(GVArrayPtr varray, + const CPPType &to_type, + const DataTypeConversions &conversions) + : GVArray(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_impl(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_impl(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 GVMutableArray { + private: + GVMutableArrayPtr varray_; + const CPPType &from_type_; + ConversionFunctions old_to_new_conversions_; + ConversionFunctions new_to_old_conversions_; + + public: + GVMutableArray_For_ConvertedGVMutableArray(GVMutableArrayPtr varray, + const CPPType &to_type, + const DataTypeConversions &conversions) + : GVMutableArray(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_impl(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_impl(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_impl(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::GVArrayPtr DataTypeConversions::try_convert(fn::GVArrayPtr 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 std::make_unique<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); +} + +fn::GVMutableArrayPtr DataTypeConversions::try_convert(fn::GVMutableArrayPtr 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 std::make_unique<GVMutableArray_For_ConvertedGVMutableArray>( + std::move(varray), to_type, *this); +} + +} // namespace blender::nodes |