void node_group_link(bNodeTree *ntree, bNodeSocket *sock, int in_out) { node_group_expose_socket(ntree, sock, in_out); }
static void loop_sync(bNodeTree *ntree, int sync_in_out) { bNodeSocket *sock, *sync, *nsync, *mirror; ListBase *sync_lb; if (sync_in_out==SOCK_IN) { sock = ntree->outputs.first; sync = ntree->inputs.first; sync_lb = &ntree->inputs; } else { sock = ntree->inputs.first; sync = ntree->outputs.first; sync_lb = &ntree->outputs; } /* NB: the sock->storage pointer is used here directly to store the own_index int * out the mirrored socket counterpart! */ while (sock) { /* skip static and internal sockets on the sync side (preserves socket order!) */ while (sync && ((sync->flag & SOCK_INTERNAL) || !(sync->flag & SOCK_DYNAMIC))) sync = sync->next; if (sync && !(sync->flag & SOCK_INTERNAL) && (sync->flag & SOCK_DYNAMIC)) { if (sock->storage==NULL) { /* if mirror index is 0, the sockets is newly added and a new mirror must be created. */ mirror = node_group_expose_socket(ntree, sock, sync_in_out); /* store the mirror index */ sock->storage = SET_INT_IN_POINTER(mirror->own_index); mirror->storage = SET_INT_IN_POINTER(sock->own_index); /* move mirror to the right place */ BLI_remlink(sync_lb, mirror); if (sync) BLI_insertlinkbefore(sync_lb, sync, mirror); else BLI_addtail(sync_lb, mirror); } else { /* look up the mirror socket */ for (mirror=sync; mirror; mirror=mirror->next) if (mirror->own_index == GET_INT_FROM_POINTER(sock->storage)) break; /* make sure the name is the same (only for identification by user, no deeper meaning) */ BLI_strncpy(mirror->name, sock->name, sizeof(mirror->name)); /* fix the socket order if necessary */ if (mirror != sync) { BLI_remlink(sync_lb, mirror); BLI_insertlinkbefore(sync_lb, sync, mirror); } else sync = sync->next; } } sock = sock->next; } /* remaining sockets in sync_lb are leftovers from deleted sockets, remove them */ while (sync) { nsync = sync->next; if (!(sync->flag & SOCK_INTERNAL) && (sync->flag & SOCK_DYNAMIC)) node_group_remove_socket(ntree, sync, sync_in_out); sync = nsync; } }
bNode *node_group_make_from_selected(bNodeTree *ntree) { bNodeLink *link, *linkn; bNode *node, *gnode, *nextn; bNodeTree *ngroup; bNodeSocket *gsock; ListBase anim_basepaths = {NULL, NULL}; float min[2], max[2]; int totnode=0; bNodeTemplate ntemp; INIT_MINMAX2(min, max); /* is there something to group? also do some clearing */ for(node= ntree->nodes.first; node; node= node->next) { if(node->flag & NODE_SELECT) { /* no groups in groups */ if(node->type==NODE_GROUP) return NULL; DO_MINMAX2( (&node->locx), min, max); totnode++; } node->done= 0; } if(totnode==0) return NULL; /* check if all connections are OK, no unselected node has both inputs and outputs to a selection */ for(link= ntree->links.first; link; link= link->next) { if(link->fromnode && link->tonode && link->fromnode->flag & NODE_SELECT) link->tonode->done |= 1; if(link->fromnode && link->tonode && link->tonode->flag & NODE_SELECT) link->fromnode->done |= 2; } for(node= ntree->nodes.first; node; node= node->next) { if((node->flag & NODE_SELECT)==0) if(node->done==3) break; } if(node) return NULL; /* OK! new nodetree */ ngroup= ntreeAddTree("NodeGroup", ntree->type, NODE_GROUP); /* move nodes over */ for(node= ntree->nodes.first; node; node= nextn) { nextn= node->next; if(node->flag & NODE_SELECT) { /* keep track of this node's RNA "base" path (the part of the pat identifying the node) * if the old nodetree has animation data which potentially covers this node */ if (ntree->adt) { PointerRNA ptr; char *path; RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); path = RNA_path_from_ID_to_struct(&ptr); if (path) BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); } /* change node-collection membership */ BLI_remlink(&ntree->nodes, node); BLI_addtail(&ngroup->nodes, node); node->locx-= 0.5f*(min[0]+max[0]); node->locy-= 0.5f*(min[1]+max[1]); } } /* move animation data over */ if (ntree->adt) { LinkData *ld, *ldn=NULL; BKE_animdata_separate_by_basepath(&ntree->id, &ngroup->id, &anim_basepaths); /* paths + their wrappers need to be freed */ for (ld = anim_basepaths.first; ld; ld = ldn) { ldn = ld->next; MEM_freeN(ld->data); BLI_freelinkN(&anim_basepaths, ld); } } /* make group node */ ntemp.type = NODE_GROUP; ntemp.ngroup = ngroup; gnode= nodeAddNode(ntree, &ntemp); gnode->locx= 0.5f*(min[0]+max[0]); gnode->locy= 0.5f*(min[1]+max[1]); /* relink external sockets */ for(link= ntree->links.first; link; link= linkn) { linkn= link->next; if(link->fromnode && link->tonode && (link->fromnode->flag & link->tonode->flag & NODE_SELECT)) { BLI_remlink(&ntree->links, link); BLI_addtail(&ngroup->links, link); } else if(link->tonode && (link->tonode->flag & NODE_SELECT)) { gsock = node_group_expose_socket(ngroup, link->tosock, SOCK_IN); link->tosock->link = nodeAddLink(ngroup, NULL, gsock, link->tonode, link->tosock); link->tosock = node_group_add_extern_socket(ntree, &gnode->inputs, SOCK_IN, gsock); link->tonode = gnode; } else if(link->fromnode && (link->fromnode->flag & NODE_SELECT)) { /* search for existing group node socket */ for (gsock=ngroup->outputs.first; gsock; gsock=gsock->next) if (gsock->link && gsock->link->fromsock==link->fromsock) break; if (!gsock) { gsock = node_group_expose_socket(ngroup, link->fromsock, SOCK_OUT); gsock->link = nodeAddLink(ngroup, link->fromnode, link->fromsock, NULL, gsock); link->fromsock = node_group_add_extern_socket(ntree, &gnode->outputs, SOCK_OUT, gsock); } else link->fromsock = node_group_find_output(gnode, gsock); link->fromnode = gnode; } } ngroup->update |= NTREE_UPDATE; ntreeUpdateTree(ngroup); ntree->update |= NTREE_UPDATE_NODES|NTREE_UPDATE_LINKS; ntreeUpdateTree(ntree); return gnode; }