From d26165747eb091898685a6a17cfcaec13070be65 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 20 Sep 2021 18:08:47 +0200 Subject: initial support for node groups --- source/blender/blenkernel/intern/node.cc | 130 ++++++++++++++++++++++++++++--- source/blender/makesdna/DNA_node_types.h | 2 + 2 files changed, 121 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 9ef82591b52..a9814964a1b 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -53,10 +53,12 @@ #include "BLI_map.hh" #include "BLI_math.h" #include "BLI_path_util.h" +#include "BLI_set.hh" #include "BLI_stack.hh" #include "BLI_string.h" #include "BLI_string_utils.h" #include "BLI_utildefines.h" +#include "BLI_vector_set.hh" #include "BLT_translation.h" @@ -97,9 +99,11 @@ #define NODE_DEFAULT_MAX_WIDTH 700 using blender::Array; +using blender::Set; using blender::Span; using blender::Stack; using blender::Vector; +using blender::VectorSet; using namespace blender::nodes::node_tree_ref_types; /* Fallback types for undefined tree, nodes, sockets */ @@ -656,6 +660,8 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) ntree->progress = nullptr; ntree->execdata = nullptr; + ntree->output_field_dependencies = nullptr; + BLO_read_data_address(reader, &ntree->adt); BKE_animdata_blend_read_data(reader, ntree->adt); @@ -4493,12 +4499,44 @@ static bool sockets_have_links(blender::Span sockets) return false; } +using OutputFieldDependencies = Vector>>; + +static const std::optional> *get_group_output_field_dependencies( + const OutputSocketRef &output_socket) +{ + const NodeRef &node = output_socket.node(); + BLI_assert(node.is_group_node()); + bNodeTree *group = (bNodeTree *)node.bnode()->id; + if (group == nullptr) { + return nullptr; + } + if (group->output_field_dependencies == nullptr) { + return nullptr; + } + const OutputFieldDependencies *output_field_dependencies = (const OutputFieldDependencies *) + group->output_field_dependencies; + if (output_socket.index() >= output_field_dependencies->size()) { + return nullptr; + } + return &(*output_field_dependencies)[output_socket.index()]; +} + static Vector get_linked_field_input_indices(const OutputSocketRef &output_socket) { Vector indices; - for (const InputSocketRef *input_socket : output_socket.node().inputs()) { - if (is_field_socket_type((eNodeSocketDatatype)input_socket->typeinfo()->type)) { - indices.append(input_socket->index()); + const NodeRef &node = output_socket.node(); + if (node.is_group_node()) { + const std::optional> *optional_dependencies = get_group_output_field_dependencies( + output_socket); + if (optional_dependencies && optional_dependencies->has_value()) { + indices.extend(**optional_dependencies); + } + } + else { + for (const InputSocketRef *input_socket : output_socket.node().inputs()) { + if (is_field_socket_type((eNodeSocketDatatype)input_socket->typeinfo()->type)) { + indices.append(input_socket->index()); + } } } return indices; @@ -4539,6 +4577,53 @@ static Vector toposort_nodes(const NodeTreeRef &tree, bool left return toposort; } +struct SocketFieldState { + bool is_single = true; + bool is_field_source = false; + bool requires_single = false; +}; + +static std::optional> find_dependent_group_input_indices( + const InputSocketRef &group_output_socket, + const Span field_state_by_socket_id) +{ + Set handled_sockets; + Stack sockets_to_check; + + handled_sockets.add(&group_output_socket); + sockets_to_check.push(&group_output_socket); + + Set found_input_indices; + + while (!sockets_to_check.is_empty()) { + const InputSocketRef *input_socket = sockets_to_check.pop(); + for (const OutputSocketRef *origin_socket : input_socket->logically_linked_sockets()) { + const NodeRef &origin_node = origin_socket->node(); + const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()]; + if (origin_state.is_field_source) { + if (origin_node.is_group_input_node()) { + found_input_indices.add(origin_socket->index()); + } + else { + return std::nullopt; + } + } + else if (!origin_state.is_single) { + const Vector input_socket_indices = get_linked_field_input_indices(*origin_socket); + for (const int input_index : input_socket_indices) { + const InputSocketRef &origin_input_socket = origin_node.input(input_index); + if (!field_state_by_socket_id[origin_input_socket.id()].is_single) { + if (handled_sockets.add(&origin_input_socket)) { + sockets_to_check.push(&origin_input_socket); + } + } + } + } + } + } + return Vector(found_input_indices.begin(), found_input_indices.end()); +} + static void update_socket_shapes_for_fields(bNodeTree &btree) { using namespace blender; @@ -4551,11 +4636,6 @@ static void update_socket_shapes_for_fields(bNodeTree &btree) Vector toposort_left_to_right = toposort_nodes(tree, true); Vector toposort_right_to_left = toposort_nodes(tree, false); - struct SocketFieldState { - bool is_single = true; - bool requires_single = false; - }; - Array field_state_by_socket_id(tree.sockets().size()); auto check_if_node_is_adaptive = [](const NodeRef &node) { @@ -4603,6 +4683,7 @@ static void update_socket_shapes_for_fields(bNodeTree &btree) SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; if (!state.requires_single) { state.is_single = false; + state.is_field_source = true; } } } @@ -4630,7 +4711,16 @@ static void update_socket_shapes_for_fields(bNodeTree &btree) if (node_decl != nullptr) { const SocketDeclaration &socket_decl = *node_decl->outputs()[output_socket->index()]; if (socket_decl.is_field()) { - field_state_by_socket_id[output_socket->id()].is_single = false; + state.is_single = false; + state.is_field_source = true; + } + } + if (output_socket->node().is_group_node()) { + const std::optional> *optional_dependencies = + get_group_output_field_dependencies(*output_socket); + if (optional_dependencies && !optional_dependencies->has_value()) { + state.is_single = false; + state.is_field_source = true; } } const Vector input_socket_indices = get_linked_field_input_indices(*output_socket); @@ -4644,9 +4734,27 @@ static void update_socket_shapes_for_fields(bNodeTree &btree) } } + for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { + if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) { + continue; + } + + OutputFieldDependencies *output_field_dependencies = new OutputFieldDependencies(); + for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) { + std::optional> dependent_input_indices = find_dependent_group_input_indices( + *group_output_socket, field_state_by_socket_id); + output_field_dependencies->append(std::move(dependent_input_indices)); + } + if (btree.output_field_dependencies != nullptr) { + delete (OutputFieldDependencies *)btree.output_field_dependencies; + } + btree.output_field_dependencies = output_field_dependencies; + break; + } + for (const InputSocketRef *socket : tree.input_sockets()) { bNodeSocket *bsocket = socket->bsocket(); - SocketFieldState &state = field_state_by_socket_id[socket->id()]; + const SocketFieldState &state = field_state_by_socket_id[socket->id()]; if (state.requires_single) { bsocket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE; } @@ -4656,7 +4764,7 @@ static void update_socket_shapes_for_fields(bNodeTree &btree) } for (const OutputSocketRef *socket : tree.output_sockets()) { bNodeSocket *bsocket = socket->bsocket(); - SocketFieldState &state = field_state_by_socket_id[socket->id()]; + const SocketFieldState &state = field_state_by_socket_id[socket->id()]; if (state.is_single) { bsocket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE; } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index f4c88333528..d3154eaae7b 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -481,6 +481,8 @@ typedef struct bNodeTree { float view_center[2]; ListBase nodes, links; + /* Vector>>. */ + void *output_field_dependencies; /** Set init on fileread. */ int type, init; -- cgit v1.2.3