Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_node/node_relationships.cc
| Show First 20 Lines • Show All 606 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Link Viewer Operator | /** \name Link Viewer Operator | ||||
| * \{ */ | * \{ */ | ||||
| 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; | |||||
| } | |||||
| } | |||||
| static bNodeSocket *node_link_viewer_get_socket(bNodeTree *ntree, | |||||
| bNode *viewer_node, | |||||
| bNodeSocket *src_socket) | |||||
| { | |||||
| if (viewer_node->type != GEO_NODE_VIEWER) { | |||||
| return (bNodeSocket *)viewer_node->inputs.first; | |||||
| } | |||||
| 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; | |||||
| } | |||||
| static int node_link_viewer(const bContext *C, bNode *tonode) | static int node_link_viewer(const bContext *C, bNode *tonode) | ||||
| { | { | ||||
| SpaceNode *snode = CTX_wm_space_node(C); | SpaceNode *snode = CTX_wm_space_node(C); | ||||
| bNodeTree *ntree = snode->edittree; | |||||
| /* context check */ | /* context check */ | ||||
| if (tonode == nullptr || BLI_listbase_is_empty(&tonode->outputs)) { | if (tonode == nullptr || BLI_listbase_is_empty(&tonode->outputs)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { | if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* get viewer */ | /* get viewer */ | ||||
| bNode *viewer_node = nullptr; | bNode *viewer_node = nullptr; | ||||
| LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { | if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { | ||||
| if (node->flag & NODE_DO_OUTPUT) { | if (node->flag & NODE_DO_OUTPUT) { | ||||
| viewer_node = node; | viewer_node = node; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
HooglyBoogly: I'm not sure I have an answer at the moment, but we should think of a better place to put this… | |||||
Done Inline ActionsYeah, agreed, can be moved elsewhere later. JacquesLucke: Yeah, agreed, can be moved elsewhere later. | |||||
| } | } | ||||
| /* no viewer, we make one active */ | /* no viewer, we make one active */ | ||||
| if (viewer_node == nullptr) { | if (viewer_node == nullptr) { | ||||
| LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { | if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { | ||||
| node->flag |= NODE_DO_OUTPUT; | node->flag |= NODE_DO_OUTPUT; | ||||
| viewer_node = node; | viewer_node = node; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| bNodeSocket *sock = nullptr; | bNodeSocket *sock = nullptr; | ||||
| bNodeLink *link = nullptr; | bNodeLink *link = nullptr; | ||||
| /* try to find an already connected socket to cycle to the next */ | /* try to find an already connected socket to cycle to the next */ | ||||
| if (viewer_node) { | if (viewer_node) { | ||||
| link = nullptr; | link = nullptr; | ||||
| for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) { | for (link = (bNodeLink *)ntree->links.first; link; link = link->next) { | ||||
| if (link->tonode == viewer_node && link->fromnode == tonode) { | if (link->tonode == viewer_node && link->fromnode == tonode) { | ||||
| if (viewer_node->type == GEO_NODE_VIEWER) { | |||||
| break; | |||||
| } | |||||
| if (link->tosock == viewer_node->inputs.first) { | if (link->tosock == viewer_node->inputs.first) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (link) { | if (link) { | ||||
| /* unlink existing connection */ | /* unlink existing connection */ | ||||
| sock = link->fromsock; | sock = link->fromsock; | ||||
| nodeRemLink(snode->edittree, link); | nodeRemLink(ntree, link); | ||||
| /* find a socket after the previously connected socket */ | /* 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) { | for (sock = sock->next; sock; sock = sock->next) { | ||||
| if (!nodeSocketIsHidden(sock)) { | if (!nodeSocketIsHidden(sock)) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| if (tonode) { | if (tonode) { | ||||
| /* Find a selected socket that overrides the socket to connect to */ | /* 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; | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) { | LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) { | ||||
| if (!nodeSocketIsHidden(sock2) && sock2->flag & SELECT) { | if (!nodeSocketIsHidden(sock2) && sock2->flag & SELECT) { | ||||
| sock = sock2; | sock = sock2; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| /* find a socket starting from the first socket */ | /* find a socket starting from the first socket */ | ||||
| if (!sock) { | 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; | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| for (sock = (bNodeSocket *)tonode->outputs.first; sock; sock = sock->next) { | for (sock = (bNodeSocket *)tonode->outputs.first; sock; sock = sock->next) { | ||||
| if (!nodeSocketIsHidden(sock)) { | if (!nodeSocketIsHidden(sock)) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| if (sock) { | if (sock) { | ||||
| /* add a new viewer if none exists yet */ | /* add a new viewer if none exists yet */ | ||||
| if (!viewer_node) { | if (!viewer_node) { | ||||
| /* XXX location is a quick hack, just place it next to the linked socket */ | /* 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; | 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); | viewer_node = node_add_node(C, nullptr, viewer_type, sock->locx + 100, sock->locy); | ||||
| if (!viewer_node) { | if (!viewer_node) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| link = nullptr; | link = nullptr; | ||||
| } | } | ||||
| else { | |||||
| bNodeSocket *viewer_socket = node_link_viewer_get_socket(ntree, viewer_node, sock); | |||||
| if (viewer_socket == nullptr) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| /* get link to viewer */ | /* get link to viewer */ | ||||
| for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) { | for (link = (bNodeLink *)ntree->links.first; link; link = link->next) { | ||||
| if (link->tonode == viewer_node && link->tosock == viewer_node->inputs.first) { | if (link->tonode == viewer_node && link->tosock == viewer_socket) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| if (link == nullptr) { | if (link == nullptr) { | ||||
| nodeAddLink( | nodeAddLink(ntree, tonode, sock, viewer_node, viewer_socket); | ||||
| snode->edittree, tonode, sock, viewer_node, (bNodeSocket *)viewer_node->inputs.first); | |||||
| } | } | ||||
| else { | else { | ||||
| link->fromnode = tonode; | link->fromnode = tonode; | ||||
| link->fromsock = sock; | link->fromsock = sock; | ||||
| /* make sure the dependency sorting is updated */ | /* make sure the dependency sorting is updated */ | ||||
| snode->edittree->update |= NTREE_UPDATE_LINKS; | ntree->update |= NTREE_UPDATE_LINKS; | ||||
| } | } | ||||
| if (ED_node_is_geometry(snode)) { | if (ED_node_is_geometry(snode)) { | ||||
| ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_node); | ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_node); | ||||
| } | } | ||||
| ntreeUpdateTree(CTX_data_main(C), snode->edittree); | ntreeUpdateTree(CTX_data_main(C), ntree); | ||||
| snode_update(snode, viewer_node); | snode_update(snode, viewer_node); | ||||
| DEG_id_tag_update(&snode->edittree->id, 0); | DEG_id_tag_update(&ntree->id, 0); | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) | static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| SpaceNode *snode = CTX_wm_space_node(C); | SpaceNode *snode = CTX_wm_space_node(C); | ||||
| ▲ Show 20 Lines • Show All 1,706 Lines • Show Last 20 Lines | |||||
I'm not sure I have an answer at the moment, but we should think of a better place to put this and custom_data_type_to_socket_type