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/editors/space_node/node_relationships.cc')
-rw-r--r--source/blender/editors/space_node/node_relationships.cc360
1 files changed, 243 insertions, 117 deletions
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index b69e7e98bca..76aad684b4c 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -57,8 +57,12 @@
#include "BLT_translation.h"
+#include "NOD_node_tree_ref.hh"
+
#include "node_intern.h" /* own include */
+using namespace blender::nodes::node_tree_ref_types;
+
/* -------------------------------------------------------------------- */
/** \name Relations Helpers
* \{ */
@@ -612,160 +616,282 @@ static void snode_autoconnect(Main *bmain,
/** \name Link Viewer Operator
* \{ */
-static int node_link_viewer(const bContext *C, bNode *tonode)
-{
- SpaceNode *snode = CTX_wm_space_node(C);
+namespace blender::ed::nodes::viewer_linking {
- /* context check */
- if (tonode == nullptr || BLI_listbase_is_empty(&tonode->outputs)) {
- return OPERATOR_CANCELLED;
+/* Depending on the node tree type, different socket types are supported by viewer nodes. */
+static bool socket_can_be_viewed(const OutputSocketRef &socket)
+{
+ if (nodeSocketIsHidden(socket.bsocket())) {
+ return false;
}
- if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) {
- return OPERATOR_CANCELLED;
+ if (socket.idname() == "NodeSocketVirtual") {
+ return false;
}
+ if (socket.tree().btree()->type != NTREE_GEOMETRY) {
+ return true;
+ }
+ return ELEM(socket.typeinfo()->type,
+ SOCK_GEOMETRY,
+ SOCK_FLOAT,
+ SOCK_VECTOR,
+ SOCK_INT,
+ SOCK_BOOLEAN,
+ SOCK_RGBA);
+}
- /* get viewer */
- bNode *viewer_node = nullptr;
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) {
- if (node->flag & NODE_DO_OUTPUT) {
- viewer_node = node;
- break;
- }
- }
+static CustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type)
+{
+ switch (socket_type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_VECTOR:
+ return CD_PROP_FLOAT3;
+ case SOCK_BOOLEAN:
+ return CD_PROP_BOOL;
+ case SOCK_RGBA:
+ return CD_PROP_COLOR;
+ default:
+ /* Fallback. */
+ return CD_AUTO_FROM_NAME;
}
- /* no viewer, we make one active */
- if (viewer_node == nullptr) {
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) {
- node->flag |= NODE_DO_OUTPUT;
- viewer_node = node;
- break;
+}
+
+/**
+ * Find the socket to link to in a viewer node.
+ */
+static bNodeSocket *node_link_viewer_get_socket(bNodeTree *ntree,
+ bNode *viewer_node,
+ bNodeSocket *src_socket)
+{
+ if (viewer_node->type != GEO_NODE_VIEWER) {
+ /* In viewer nodes in the compositor, only the first input should be linked to. */
+ return (bNodeSocket *)viewer_node->inputs.first;
+ }
+ /* For the geometry nodes viewer, find the socket with the correct type. */
+ LISTBASE_FOREACH (bNodeSocket *, viewer_socket, &viewer_node->inputs) {
+ if (viewer_socket->type == src_socket->type) {
+ if (viewer_socket->type == SOCK_GEOMETRY) {
+ return viewer_socket;
}
+ NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node->storage;
+ const CustomDataType data_type = socket_type_to_custom_data_type(
+ (eNodeSocketDatatype)src_socket->type);
+ BLI_assert(data_type != CD_AUTO_FROM_NAME);
+ storage->data_type = data_type;
+ nodeUpdate(ntree, viewer_node);
+ return viewer_socket;
}
}
+ return nullptr;
+}
- bNodeSocket *sock = nullptr;
- bNodeLink *link = nullptr;
+static bool is_viewer_node(const NodeRef &node)
+{
+ return ELEM(node.bnode()->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER);
+}
- /* try to find an already connected socket to cycle to the next */
- if (viewer_node) {
- link = nullptr;
+static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree)
+{
+ Vector<const NodeRef *> viewer_nodes;
+ for (const NodeRef *node : tree.nodes()) {
+ if (is_viewer_node(*node)) {
+ viewer_nodes.append(node);
+ }
+ }
+ return viewer_nodes;
+}
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
- if (link->tonode == viewer_node && link->fromnode == tonode) {
- if (link->tosock == viewer_node->inputs.first) {
- break;
- }
- }
+static bool is_viewer_socket_in_viewer(const InputSocketRef &socket)
+{
+ const NodeRef &node = socket.node();
+ BLI_assert(is_viewer_node(node));
+ if (node.typeinfo()->type == GEO_NODE_VIEWER) {
+ return true;
+ }
+ return socket.index() == 0;
+}
+
+static bool is_linked_to_viewer(const OutputSocketRef &socket, const NodeRef &viewer_node)
+{
+ for (const InputSocketRef *target_socket : socket.directly_linked_sockets()) {
+ if (&target_socket->node() != &viewer_node) {
+ continue;
+ }
+ if (!target_socket->is_available()) {
+ continue;
+ }
+ if (is_viewer_socket_in_viewer(*target_socket)) {
+ return true;
}
- if (link) {
- /* unlink existing connection */
- sock = link->fromsock;
- nodeRemLink(snode->edittree, link);
+ }
+ return false;
+}
- /* find a socket after the previously connected socket */
- if (ED_node_is_geometry(snode)) {
- /* Geometry nodes viewer only supports geometry sockets for now. */
- for (sock = sock->next; sock; sock = sock->next) {
- if (sock->type == SOCK_GEOMETRY && !nodeSocketIsHidden(sock)) {
- break;
- }
- }
- }
- else {
- for (sock = sock->next; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock)) {
- break;
- }
- }
+static int get_default_viewer_type(const bContext *C)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ return ED_node_is_compositor(snode) ? CMP_NODE_VIEWER : GEO_NODE_VIEWER;
+}
+
+static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode &viewer_node)
+{
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &btree.links) {
+ if (link->tonode == &viewer_node) {
+ if (link->tosock->flag & SOCK_UNAVAIL) {
+ nodeRemLink(&btree, link);
}
}
}
+}
- if (tonode) {
- /* Find a selected socket that overrides the socket to connect to */
- if (ED_node_is_geometry(snode)) {
- /* Geometry nodes viewer only supports geometry sockets for now. */
- LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) {
- if (sock2->type == SOCK_GEOMETRY && !nodeSocketIsHidden(sock2) && sock2->flag & SELECT) {
- sock = sock2;
- break;
- }
- }
+static const NodeRef *get_existing_viewer(const NodeTreeRef &tree)
+{
+ Vector<const NodeRef *> viewer_nodes = find_viewer_nodes(tree);
+
+ /* Check if there is already an active viewer node that should be used. */
+ for (const NodeRef *viewer_node : viewer_nodes) {
+ if (viewer_node->bnode()->flag & NODE_DO_OUTPUT) {
+ return viewer_node;
}
- else {
- LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) {
- if (!nodeSocketIsHidden(sock2) && sock2->flag & SELECT) {
- sock = sock2;
- break;
- }
- }
+ }
+
+ /* If no active but non-active viewers exist, make one active. */
+ if (!viewer_nodes.is_empty()) {
+ viewer_nodes[0]->bnode()->flag |= NODE_DO_OUTPUT;
+ return viewer_nodes[0];
+ }
+ return nullptr;
+}
+
+static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *active_viewer_node,
+ const NodeRef &node_to_view)
+{
+ /* Check if any of the output sockets is selected, which is the case when the user just clicked
+ * on the socket. */
+ for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ if (output_socket->bsocket()->flag & SELECT) {
+ return output_socket;
}
}
- /* find a socket starting from the first socket */
- if (!sock) {
- if (ED_node_is_geometry(snode)) {
- /* Geometry nodes viewer only supports geometry sockets for now. */
- for (sock = (bNodeSocket *)tonode->outputs.first; sock; sock = sock->next) {
- if (sock->type == SOCK_GEOMETRY && !nodeSocketIsHidden(sock)) {
- break;
- }
+ const OutputSocketRef *last_socket_linked_to_viewer = nullptr;
+ if (active_viewer_node != nullptr) {
+ for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ if (!socket_can_be_viewed(*output_socket)) {
+ continue;
}
- }
- else {
- for (sock = (bNodeSocket *)tonode->outputs.first; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock)) {
- break;
- }
+ if (is_linked_to_viewer(*output_socket, *active_viewer_node)) {
+ last_socket_linked_to_viewer = output_socket;
}
}
}
-
- if (sock) {
- /* add a new viewer if none exists yet */
- if (!viewer_node) {
- /* XXX location is a quick hack, just place it next to the linked socket */
- const int viewer_type = ED_node_is_compositor(snode) ? CMP_NODE_VIEWER : GEO_NODE_VIEWER;
- viewer_node = node_add_node(C, nullptr, viewer_type, sock->locx + 100, sock->locy);
- if (!viewer_node) {
- return OPERATOR_CANCELLED;
+ if (last_socket_linked_to_viewer == nullptr) {
+ /* If no output is connected to a viewer, use the first output that can be viewed. */
+ for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ if (socket_can_be_viewed(*output_socket)) {
+ return output_socket;
}
-
- link = nullptr;
}
- else {
- /* get link to viewer */
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
- if (link->tonode == viewer_node && link->tosock == viewer_node->inputs.first) {
- break;
- }
+ }
+ else {
+ /* Pick the next socket to be linked to the viewer. */
+ const int tot_outputs = node_to_view.outputs().size();
+ for (const int offset : IndexRange(1, tot_outputs - 1)) {
+ const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs;
+ const OutputSocketRef &output_socket = node_to_view.output(index);
+ if (!socket_can_be_viewed(output_socket)) {
+ continue;
+ }
+ if (is_linked_to_viewer(output_socket, *active_viewer_node)) {
+ continue;
}
+ return &output_socket;
}
+ }
+ return nullptr;
+}
- if (link == nullptr) {
- nodeAddLink(
- snode->edittree, tonode, sock, viewer_node, (bNodeSocket *)viewer_node->inputs.first);
- }
- else {
- link->fromnode = tonode;
- link->fromsock = sock;
- /* make sure the dependency sorting is updated */
- snode->edittree->update |= NTREE_UPDATE_LINKS;
+static int link_socket_to_viewer(const bContext *C,
+ bNode *viewer_bnode,
+ bNode *bnode_to_view,
+ bNodeSocket *bsocket_to_view)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *btree = snode->edittree;
+
+ if (viewer_bnode == nullptr) {
+ /* Create a new viewer node if none exists. */
+ const int viewer_type = get_default_viewer_type(C);
+ viewer_bnode = node_add_node(
+ C, nullptr, viewer_type, bsocket_to_view->locx + 100, bsocket_to_view->locy);
+ if (viewer_bnode == nullptr) {
+ return OPERATOR_CANCELLED;
}
- if (ED_node_is_geometry(snode)) {
- ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_node);
+ }
+
+ bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, viewer_bnode, bsocket_to_view);
+ if (viewer_bsocket == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bNodeLink *link_to_change = nullptr;
+ LISTBASE_FOREACH (bNodeLink *, link, &btree->links) {
+ if (link->tosock == viewer_bsocket) {
+ link_to_change = link;
+ break;
}
+ }
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_update(snode, viewer_node);
- DEG_id_tag_update(&snode->edittree->id, 0);
+ if (link_to_change == nullptr) {
+ nodeAddLink(btree, bnode_to_view, bsocket_to_view, viewer_bnode, viewer_bsocket);
+ }
+ else {
+ link_to_change->fromnode = bnode_to_view;
+ link_to_change->fromsock = bsocket_to_view;
+ btree->update |= NTREE_UPDATE_LINKS;
}
+ remove_links_to_unavailable_viewer_sockets(*btree, *viewer_bnode);
+
+ if (btree->type == NTREE_GEOMETRY) {
+ ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_bnode);
+ }
+
+ ntreeUpdateTree(CTX_data_main(C), btree);
+ snode_update(snode, viewer_bnode);
+ DEG_id_tag_update(&btree->id, 0);
+
return OPERATOR_FINISHED;
}
+static int node_link_viewer(const bContext *C, bNode *bnode_to_view)
+{
+ if (bnode_to_view == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *btree = snode->edittree;
+
+ const NodeTreeRef tree{btree};
+ const NodeRef &node_to_view = *tree.find_node(*bnode_to_view);
+ const NodeRef *active_viewer_node = get_existing_viewer(tree);
+
+ const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node,
+ node_to_view);
+ if (socket_to_view == nullptr) {
+ return OPERATOR_FINISHED;
+ }
+
+ bNodeSocket *bsocket_to_view = socket_to_view->bsocket();
+ bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr;
+ return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view);
+}
+
+} // namespace blender::ed::nodes::viewer_linking
+
static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceNode *snode = CTX_wm_space_node(C);
@@ -777,7 +903,7 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (node_link_viewer(C, node) == OPERATOR_CANCELLED) {
+ if (blender::ed::nodes::viewer_linking::node_link_viewer(C, node) == OPERATOR_CANCELLED) {
return OPERATOR_CANCELLED;
}