Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/intern')
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc18
-rw-r--r--source/blender/nodes/intern/extern_implementations.cc35
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc79
-rw-r--r--source/blender/nodes/intern/math_functions.cc12
-rw-r--r--source/blender/nodes/intern/node_common.cc163
-rw-r--r--source/blender/nodes/intern/node_common.h10
-rw-r--r--source/blender/nodes/intern/node_declaration.cc8
-rw-r--r--source/blender/nodes/intern/node_exec.cc2
-rw-r--r--source/blender/nodes/intern/node_exec.h2
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc19
-rw-r--r--source/blender/nodes/intern/node_socket.cc108
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc184
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc8
-rw-r--r--source/blender/nodes/intern/node_util.c119
-rw-r--r--source/blender/nodes/intern/node_util.h67
-rw-r--r--source/blender/nodes/intern/socket_search_link.cc199
-rw-r--r--source/blender/nodes/intern/type_conversions.cc347
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 &params,
+ 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 &params) {
+ 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 &params,
+ 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 &params) {
+ 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(&params.node_tree, &params.node, &params.socket, &node, new_node_socket);
+ }
+ });
+ }
+}
+
+void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params)
+{
+ 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