Blender  V2.93
node_group.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <stdlib.h>
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "DNA_anim_types.h"
29 #include "DNA_node_types.h"
30 
31 #include "BLI_linklist.h"
32 #include "BLI_listbase.h"
33 #include "BLI_math.h"
34 #include "BLI_string.h"
35 
36 #include "BLT_translation.h"
37 
38 #include "BKE_action.h"
39 #include "BKE_animsys.h"
40 #include "BKE_context.h"
41 #include "BKE_lib_id.h"
42 #include "BKE_main.h"
43 #include "BKE_report.h"
44 
45 #include "DEG_depsgraph_build.h"
46 
47 #include "ED_node.h" /* own include */
48 #include "ED_render.h"
49 #include "ED_screen.h"
50 
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53 
54 #include "WM_api.h"
55 #include "WM_types.h"
56 
57 #include "UI_resources.h"
58 
59 #include "NOD_common.h"
60 #include "NOD_socket.h"
61 #include "node_intern.h" /* own include */
62 
63 /* -------------------------------------------------------------------- */
68 {
70  SpaceNode *snode = CTX_wm_space_node(C);
71 
72  /* Group operators only defined for standard node tree types.
73  * Disabled otherwise to allow pynodes define their own operators
74  * with same keymap.
75  */
76  if (STR_ELEM(snode->tree_idname,
77  "ShaderNodeTree",
78  "CompositorNodeTree",
79  "TextureNodeTree",
80  "GeometryNodeTree")) {
81  return true;
82  }
83  }
84  return false;
85 }
86 
88 {
90  SpaceNode *snode = CTX_wm_space_node(C);
91 
92  /* Group operators only defined for standard node tree types.
93  * Disabled otherwise to allow pynodes define their own operators
94  * with same keymap.
95  */
96  if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode) ||
97  ED_node_is_geometry(snode)) {
98  return true;
99  }
100  }
101  return false;
102 }
103 
104 static const char *group_ntree_idname(bContext *C)
105 {
106  SpaceNode *snode = CTX_wm_space_node(C);
107  return snode->tree_idname;
108 }
109 
111 {
112  SpaceNode *snode = CTX_wm_space_node(C);
113 
114  if (ED_node_is_shader(snode)) {
115  return "ShaderNodeGroup";
116  }
117  if (ED_node_is_compositor(snode)) {
118  return "CompositorNodeGroup";
119  }
120  if (ED_node_is_texture(snode)) {
121  return "TextureNodeGroup";
122  }
123  if (ED_node_is_geometry(snode)) {
124  return "GeometryNodeGroup";
125  }
126 
127  return "";
128 }
129 
130 static bNode *node_group_get_active(bContext *C, const char *node_idname)
131 {
132  SpaceNode *snode = CTX_wm_space_node(C);
133  bNode *node = nodeGetActive(snode->edittree);
134 
135  if (node && STREQ(node->idname, node_idname)) {
136  return node;
137  }
138  return NULL;
139 }
140 
143 /* -------------------------------------------------------------------- */
148 {
149  SpaceNode *snode = CTX_wm_space_node(C);
150  const char *node_idname = node_group_idname(C);
151  const bool exit = RNA_boolean_get(op->ptr, "exit");
152 
154 
155  bNode *gnode = node_group_get_active(C, node_idname);
156 
157  if (gnode && !exit) {
158  bNodeTree *ngroup = (bNodeTree *)gnode->id;
159 
160  if (ngroup) {
161  ED_node_tree_push(snode, ngroup, gnode);
162  }
163  }
164  else {
165  ED_node_tree_pop(snode);
166  }
167 
169 
170  return OPERATOR_FINISHED;
171 }
172 
174 {
175  /* identifiers */
176  ot->name = "Edit Group";
177  ot->description = "Edit node group";
178  ot->idname = "NODE_OT_group_edit";
179 
180  /* api callbacks */
183 
184  /* flags */
186 
187  RNA_def_boolean(ot->srna, "exit", false, "Exit", "");
188 }
189 
192 /* -------------------------------------------------------------------- */
201  const char *dst_basepath)
202 {
203  AnimationBasePathChange *basepath_change = MEM_callocN(sizeof(*basepath_change), AT);
204  basepath_change->src_basepath = src_basepath;
205  basepath_change->dst_basepath = dst_basepath;
206  return basepath_change;
207 }
208 
210 {
211  if (basepath_change->src_basepath != basepath_change->dst_basepath) {
212  MEM_freeN((void *)basepath_change->src_basepath);
213  }
214  MEM_freeN((void *)basepath_change->dst_basepath);
215  MEM_freeN(basepath_change);
216 }
217 
218 /* returns 1 if its OK */
219 static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
220 {
221  /* clear new pointers, set in copytree */
223  node->new_node = NULL;
224  }
225 
226  ListBase anim_basepaths = {NULL, NULL};
227  LinkNode *nodes_delayed_free = NULL;
228  bNodeTree *ngroup = (bNodeTree *)gnode->id;
229 
230  /* wgroup is a temporary copy of the NodeTree we're merging in
231  * - all of wgroup's nodes are copied across to their new home
232  * - ngroup (i.e. the source NodeTree) is left unscathed
233  * - temp copy. do change ID usercount for the copies
234  */
235  bNodeTree *wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true);
236 
237  /* Add the nodes into the ntree */
238  LISTBASE_FOREACH_MUTABLE (bNode *, node, &wgroup->nodes) {
239  /* Remove interface nodes.
240  * This also removes remaining links to and from interface nodes.
241  */
243  /* We must delay removal since sockets will reference this node. see: T52092 */
244  BLI_linklist_prepend(&nodes_delayed_free, node);
245  }
246 
247  /* keep track of this node's RNA "base" path (the part of the path identifying the node)
248  * if the old nodetree has animation data which potentially covers this node
249  */
250  const char *old_animation_basepath = NULL;
251  if (wgroup->adt) {
252  PointerRNA ptr;
253  RNA_pointer_create(&wgroup->id, &RNA_Node, node, &ptr);
254  old_animation_basepath = RNA_path_from_ID_to_struct(&ptr);
255  }
256 
257  /* migrate node */
258  BLI_remlink(&wgroup->nodes, node);
260 
261  /* ensure unique node name in the node tree */
263 
264  if (wgroup->adt) {
265  PointerRNA ptr;
267  const char *new_animation_basepath = RNA_path_from_ID_to_struct(&ptr);
268  BLI_addtail(&anim_basepaths,
269  animation_basepath_change_new(old_animation_basepath, new_animation_basepath));
270  }
271 
272  if (!node->parent) {
273  node->locx += gnode->locx;
274  node->locy += gnode->locy;
275  }
276 
277  node->flag |= NODE_SELECT;
278  }
279 
280  bNodeLink *glinks_first = ntree->links.last;
281 
282  /* Add internal links to the ntree */
283  LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &wgroup->links) {
284  BLI_remlink(&wgroup->links, link);
285  BLI_addtail(&ntree->links, link);
286  }
287 
288  bNodeLink *glinks_last = ntree->links.last;
289 
290  /* and copy across the animation,
291  * note that the animation data's action can be NULL here */
292  if (wgroup->adt) {
293  bAction *waction;
294 
295  /* firstly, wgroup needs to temporary dummy action
296  * that can be destroyed, as it shares copies */
297  waction = wgroup->adt->action = (bAction *)BKE_id_copy(bmain, &wgroup->adt->action->id);
298 
299  /* now perform the moving */
300  BKE_animdata_transfer_by_basepath(bmain, &wgroup->id, &ntree->id, &anim_basepaths);
301 
302  /* paths + their wrappers need to be freed */
303  LISTBASE_FOREACH_MUTABLE (AnimationBasePathChange *, basepath_change, &anim_basepaths) {
304  animation_basepath_change_free(basepath_change);
305  }
306 
307  /* free temp action too */
308  if (waction) {
309  BKE_id_free(bmain, waction);
310  wgroup->adt->action = NULL;
311  }
312  }
313 
314  /* free the group tree (takes care of user count) */
315  BKE_id_free(bmain, wgroup);
316 
317  /* restore external links to and from the gnode */
318 
319  /* input links */
320  if (glinks_first != NULL) {
321  for (bNodeLink *link = glinks_first->next; link != glinks_last->next; link = link->next) {
322  if (link->fromnode->type == NODE_GROUP_INPUT) {
323  const char *identifier = link->fromsock->identifier;
324  int num_external_links = 0;
325 
326  /* find external links to this input */
327  for (bNodeLink *tlink = ntree->links.first; tlink != glinks_first->next;
328  tlink = tlink->next) {
329  if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
330  nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
331  num_external_links++;
332  }
333  }
334 
335  /* if group output is not externally linked,
336  * convert the constant input value to ensure somewhat consistent behavior */
337  if (num_external_links == 0) {
338  /* TODO */
339 #if 0
340  bNodeSocket *sock = node_group_find_input_socket(gnode, identifier);
341  BLI_assert(sock);
342 
343  nodeSocketCopy(
344  ntree, link->tosock->new_sock, link->tonode->new_node, ntree, sock, gnode);
345 #endif
346  }
347  }
348  }
349 
350  /* Also iterate over new links to cover passthrough links. */
351  glinks_last = ntree->links.last;
352 
353  /* output links */
354  for (bNodeLink *link = ntree->links.first; link != glinks_first->next; link = link->next) {
355  if (link->fromnode == gnode) {
356  const char *identifier = link->fromsock->identifier;
357  int num_internal_links = 0;
358 
359  /* find internal links to this output */
360  for (bNodeLink *tlink = glinks_first->next; tlink != glinks_last->next;
361  tlink = tlink->next) {
362  /* only use active output node */
363  if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) {
364  if (STREQ(tlink->tosock->identifier, identifier)) {
365  nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
366  num_internal_links++;
367  }
368  }
369  }
370 
371  /* if group output is not internally linked,
372  * convert the constant output value to ensure somewhat consistent behavior */
373  if (num_internal_links == 0) {
374  /* TODO */
375 #if 0
376  bNodeSocket *sock = node_group_find_output_socket(gnode, identifier);
377  BLI_assert(sock);
378 
379  nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode);
380 #endif
381  }
382  }
383  }
384  }
385 
386  while (nodes_delayed_free) {
387  bNode *node = BLI_linklist_pop(&nodes_delayed_free);
388  nodeRemoveNode(bmain, ntree, node, false);
389  }
390 
391  /* delete the group instance and dereference group tree */
392  nodeRemoveNode(bmain, ntree, gnode, true);
393 
395 
396  return 1;
397 }
398 
400 {
401  Main *bmain = CTX_data_main(C);
402  SpaceNode *snode = CTX_wm_space_node(C);
403  const char *node_idname = node_group_idname(C);
404 
406 
407  bNode *gnode = node_group_get_active(C, node_idname);
408  if (!gnode) {
409  return OPERATOR_CANCELLED;
410  }
411 
412  if (gnode->id && node_group_ungroup(bmain, snode->edittree, gnode)) {
413  ntreeUpdateTree(bmain, snode->nodetree);
414  }
415  else {
416  BKE_report(op->reports, RPT_WARNING, "Cannot ungroup");
417  return OPERATOR_CANCELLED;
418  }
419 
420  snode_notify(C, snode);
421  snode_dag_update(C, snode);
422 
423  return OPERATOR_FINISHED;
424 }
425 
427 {
428  /* identifiers */
429  ot->name = "Ungroup";
430  ot->description = "Ungroup selected nodes";
431  ot->idname = "NODE_OT_group_ungroup";
432 
433  /* api callbacks */
436 
437  /* flags */
439 }
440 
443 /* -------------------------------------------------------------------- */
447 /* returns 1 if its OK */
449  Main *bmain, bNodeTree *ntree, bNodeTree *ngroup, float offx, float offy, int make_copy)
450 {
451  /* deselect all nodes in the target tree */
453  nodeSetSelected(node, false);
454  }
455 
456  /* clear new pointers, set in BKE_node_copy_ex(). */
457  LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
458  node->new_node = NULL;
459  }
460 
461  ListBase anim_basepaths = {NULL, NULL};
462 
463  /* add selected nodes into the ntree */
464  LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup->nodes) {
465  if (!(node->flag & NODE_SELECT)) {
466  continue;
467  }
468 
469  /* ignore interface nodes */
471  nodeSetSelected(node, false);
472  continue;
473  }
474 
475  bNode *newnode;
476  if (make_copy) {
477  /* make a copy */
479  }
480  else {
481  /* use the existing node */
482  newnode = node;
483  }
484 
485  /* keep track of this node's RNA "base" path (the part of the path identifying the node)
486  * if the old nodetree has animation data which potentially covers this node
487  */
488  if (ngroup->adt) {
489  PointerRNA ptr;
490  char *path;
491 
492  RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &ptr);
494 
495  if (path) {
496  BLI_addtail(&anim_basepaths, animation_basepath_change_new(path, path));
497  }
498  }
499 
500  /* ensure valid parent pointers, detach if parent stays inside the group */
501  if (newnode->parent && !(newnode->parent->flag & NODE_SELECT)) {
502  nodeDetachNode(newnode);
503  }
504 
505  /* migrate node */
506  BLI_remlink(&ngroup->nodes, newnode);
507  BLI_addtail(&ntree->nodes, newnode);
508 
509  /* ensure unique node name in the node tree */
510  nodeUniqueName(ntree, newnode);
511 
512  if (!newnode->parent) {
513  newnode->locx += offx;
514  newnode->locy += offy;
515  }
516  }
517 
518  /* add internal links to the ntree */
519  LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup->links) {
520  const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
521  const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
522 
523  if (make_copy) {
524  /* make a copy of internal links */
525  if (fromselect && toselect) {
527  link->fromnode->new_node,
528  link->fromsock->new_sock,
529  link->tonode->new_node,
530  link->tosock->new_sock);
531  }
532  }
533  else {
534  /* move valid links over, delete broken links */
535  if (fromselect && toselect) {
536  BLI_remlink(&ngroup->links, link);
537  BLI_addtail(&ntree->links, link);
538  }
539  else if (fromselect || toselect) {
540  nodeRemLink(ngroup, link);
541  }
542  }
543  }
544 
545  /* and copy across the animation,
546  * note that the animation data's action can be NULL here */
547  if (ngroup->adt) {
548  /* now perform the moving */
549  BKE_animdata_transfer_by_basepath(bmain, &ngroup->id, &ntree->id, &anim_basepaths);
550 
551  /* paths + their wrappers need to be freed */
552  LISTBASE_FOREACH_MUTABLE (AnimationBasePathChange *, basepath_change, &anim_basepaths) {
553  animation_basepath_change_free(basepath_change);
554  }
555  }
556 
558  if (!make_copy) {
560  }
561 
562  return 1;
563 }
564 
569 
570 /* Operator Property */
572  {NODE_GS_COPY, "COPY", 0, "Copy", "Copy to parent node tree, keep group intact"},
573  {NODE_GS_MOVE, "MOVE", 0, "Move", "Move to parent node tree, remove from group"},
574  {0, NULL, 0, NULL, NULL},
575 };
576 
578 {
579  Main *bmain = CTX_data_main(C);
580  SpaceNode *snode = CTX_wm_space_node(C);
581  int type = RNA_enum_get(op->ptr, "type");
582 
584 
585  /* are we inside of a group? */
586  bNodeTree *ngroup = snode->edittree;
587  bNodeTree *nparent = ED_node_tree_get(snode, 1);
588  if (!nparent) {
589  BKE_report(op->reports, RPT_WARNING, "Not inside node group");
590  return OPERATOR_CANCELLED;
591  }
592  /* get node tree offset */
593  float offx, offy;
594  space_node_group_offset(snode, &offx, &offy);
595 
596  switch (type) {
597  case NODE_GS_COPY:
598  if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, true)) {
599  BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes");
600  return OPERATOR_CANCELLED;
601  }
602  break;
603  case NODE_GS_MOVE:
604  if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, false)) {
605  BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes");
606  return OPERATOR_CANCELLED;
607  }
608  break;
609  }
610 
611  /* switch to parent tree */
612  ED_node_tree_pop(snode);
613 
615 
616  snode_notify(C, snode);
617  snode_dag_update(C, snode);
618 
619  return OPERATOR_FINISHED;
620 }
621 
623  wmOperator *UNUSED(op),
624  const wmEvent *UNUSED(event))
625 {
627  C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE);
628  uiLayout *layout = UI_popup_menu_layout(pup);
629 
631  uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_COPY);
632  uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_MOVE);
633 
634  UI_popup_menu_end(C, pup);
635 
636  return OPERATOR_INTERFACE;
637 }
638 
640 {
641  /* identifiers */
642  ot->name = "Separate";
643  ot->description = "Separate selected nodes from the node group";
644  ot->idname = "NODE_OT_group_separate";
645 
646  /* api callbacks */
650 
651  /* flags */
653 
655 }
656 
659 /* -------------------------------------------------------------------- */
664 {
665  return (node != gnode && !ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) &&
666  (node->flag & NODE_SELECT));
667 }
668 
670  bNode *gnode,
671  const char *ntree_idname,
672  struct ReportList *reports)
673 {
674  int ok = true;
675 
676  /* make a local pseudo node tree to pass to the node poll functions */
677  bNodeTree *ngroup = ntreeAddTree(NULL, "Pseudo Node Group", ntree_idname);
678 
679  /* check poll functions for selected nodes */
681  if (node_group_make_use_node(node, gnode)) {
682  const char *disabled_hint = NULL;
683  if (node->typeinfo->poll_instance &&
684  !node->typeinfo->poll_instance(node, ngroup, &disabled_hint)) {
685  if (disabled_hint) {
686  BKE_reportf(reports,
687  RPT_WARNING,
688  "Can not add node '%s' in a group:\n %s",
689  node->name,
690  disabled_hint);
691  }
692  else {
693  BKE_reportf(reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
694  }
695  ok = false;
696  break;
697  }
698  }
699 
700  node->done = 0;
701  }
702 
703  /* free local pseudo node tree again */
704  ntreeFreeTree(ngroup);
705  MEM_freeN(ngroup);
706  if (!ok) {
707  return false;
708  }
709 
710  /* check if all connections are OK, no unselected node has both
711  * inputs and outputs to a selection */
712  LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
713  if (node_group_make_use_node(link->fromnode, gnode)) {
714  link->tonode->done |= 1;
715  }
716  if (node_group_make_use_node(link->tonode, gnode)) {
717  link->fromnode->done |= 2;
718  }
719  }
721  if (!(node->flag & NODE_SELECT) && node != gnode && node->done == 3) {
722  return false;
723  }
724  }
725  return true;
726 }
727 
729  bNodeTree *ntree, bNode *gnode, float *min, float *max, bool use_size)
730 {
731  int totselect = 0;
732 
733  INIT_MINMAX2(min, max);
735  if (node_group_make_use_node(node, gnode)) {
736  float loc[2];
737  nodeToView(node, node->offsetx, node->offsety, &loc[0], &loc[1]);
738  minmax_v2v2_v2(min, max, loc);
739  if (use_size) {
740  loc[0] += node->width;
741  loc[1] -= node->height;
742  minmax_v2v2_v2(min, max, loc);
743  }
744  totselect++;
745  }
746  }
747 
748  /* sane min/max if no selected nodes */
749  if (totselect == 0) {
750  min[0] = min[1] = max[0] = max[1] = 0.0f;
751  }
752 
753  return totselect;
754 }
755 
757 {
758  Main *bmain = CTX_data_main(C);
759  bNodeTree *ngroup = (bNodeTree *)gnode->id;
760  bool expose_visible = false;
761 
762  /* XXX rough guess, not nice but we don't have access to UI constants here ... */
763  static const float offsetx = 200;
764  static const float offsety = 0.0f;
765 
766  /* deselect all nodes in the target tree */
767  LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
768  nodeSetSelected(node, false);
769  }
770 
771  float center[2], min[2], max[2];
772  const int totselect = node_get_selected_minmax(ntree, gnode, min, max, false);
774  mul_v2_fl(center, 0.5f);
775 
776  float real_min[2], real_max[2];
777  node_get_selected_minmax(ntree, gnode, real_min, real_max, true);
778 
779  /* auto-add interface for "solo" nodes */
780  if (totselect == 1) {
781  expose_visible = true;
782  }
783 
784  ListBase anim_basepaths = {NULL, NULL};
785 
786  /* move nodes over */
788  if (node_group_make_use_node(node, gnode)) {
789  /* keep track of this node's RNA "base" path (the part of the pat identifying the node)
790  * if the old nodetree has animation data which potentially covers this node
791  */
792  if (ntree->adt) {
793  PointerRNA ptr;
794  char *path;
795 
798 
799  if (path) {
800  BLI_addtail(&anim_basepaths, animation_basepath_change_new(path, path));
801  }
802  }
803 
804  /* ensure valid parent pointers, detach if parent stays outside the group */
805  if (node->parent && !(node->parent->flag & NODE_SELECT)) {
807  }
808 
809  /* change node-collection membership */
811  BLI_addtail(&ngroup->nodes, node);
812 
813  /* ensure unique node name in the ngroup */
814  nodeUniqueName(ngroup, node);
815  }
816  }
817 
818  /* move animation data over */
819  if (ntree->adt) {
820  BKE_animdata_transfer_by_basepath(bmain, &ntree->id, &ngroup->id, &anim_basepaths);
821 
822  /* paths + their wrappers need to be freed */
823  LISTBASE_FOREACH_MUTABLE (AnimationBasePathChange *, basepath_change, &anim_basepaths) {
824  animation_basepath_change_free(basepath_change);
825  }
826  }
827 
828  /* node groups don't use internal cached data */
829  ntreeFreeCache(ngroup);
830 
831  /* create input node */
832  bNode *input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT);
833  input_node->locx = real_min[0] - center[0] - offsetx;
834  input_node->locy = -offsety;
835 
836  /* create output node */
837  bNode *output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT);
838  output_node->locx = real_max[0] - center[0] + offsetx * 0.25f;
839  output_node->locy = -offsety;
840 
841  /* relink external sockets */
843  int fromselect = node_group_make_use_node(link->fromnode, gnode);
844  int toselect = node_group_make_use_node(link->tonode, gnode);
845 
846  if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) {
847  /* remove all links to/from the gnode.
848  * this can remove link information, but there's no general way to preserve it.
849  */
850  nodeRemLink(ntree, link);
851  }
852  else if (toselect && !fromselect) {
853  bNodeSocket *link_sock;
854  bNode *link_node;
855  node_socket_skip_reroutes(&ntree->links, link->tonode, link->tosock, &link_node, &link_sock);
856  bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link_node, link_sock);
857 
858  /* update the group node and interface node sockets,
859  * so the new interface socket can be linked.
860  */
861  node_group_update(ntree, gnode);
862  node_group_input_update(ngroup, input_node);
863 
864  /* create new internal link */
865  bNodeSocket *input_sock = node_group_input_find_socket(input_node, iosock->identifier);
866  nodeAddLink(ngroup, input_node, input_sock, link->tonode, link->tosock);
867 
868  /* redirect external link */
869  link->tonode = gnode;
870  link->tosock = node_group_find_input_socket(gnode, iosock->identifier);
871  }
872  else if (fromselect && !toselect) {
873  /* First check whether the source of this link is already connected to an output.
874  * If yes, reuse that output instead of duplicating it. */
875  bool connected = false;
876  LISTBASE_FOREACH (bNodeLink *, olink, &ngroup->links) {
877  if (olink->fromsock == link->fromsock && olink->tonode == output_node) {
878  bNodeSocket *output_sock = node_group_find_output_socket(gnode,
879  olink->tosock->identifier);
880  link->fromnode = gnode;
881  link->fromsock = output_sock;
882  connected = true;
883  }
884  }
885 
886  if (!connected) {
887  bNodeSocket *link_sock;
888  bNode *link_node;
890  &ntree->links, link->fromnode, link->fromsock, &link_node, &link_sock);
891  bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link_node, link_sock);
892 
893  /* update the group node and interface node sockets,
894  * so the new interface socket can be linked.
895  */
896  node_group_update(ntree, gnode);
897  node_group_output_update(ngroup, output_node);
898 
899  /* create new internal link */
900  bNodeSocket *output_sock = node_group_output_find_socket(output_node, iosock->identifier);
901  nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock);
902 
903  /* redirect external link */
904  link->fromnode = gnode;
905  link->fromsock = node_group_find_output_socket(gnode, iosock->identifier);
906  }
907  }
908  }
909 
910  /* move internal links */
912  int fromselect = node_group_make_use_node(link->fromnode, gnode);
913  int toselect = node_group_make_use_node(link->tonode, gnode);
914 
915  if (fromselect && toselect) {
916  BLI_remlink(&ntree->links, link);
917  BLI_addtail(&ngroup->links, link);
918  }
919  }
920 
921  /* move nodes in the group to the center */
922  LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
923  if (node_group_make_use_node(node, gnode) && !node->parent) {
924  node->locx -= center[0];
925  node->locy -= center[1];
926  }
927  }
928 
929  /* expose all unlinked sockets too but only the visible ones*/
930  if (expose_visible) {
931  LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
932  if (node_group_make_use_node(node, gnode)) {
933  LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
934  bool skip = false;
935  LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
936  if (link->tosock == sock) {
937  skip = true;
938  break;
939  }
940  }
941  if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
942  skip = true;
943  }
944  if (skip) {
945  continue;
946  }
947 
948  bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
949 
950  node_group_input_update(ngroup, input_node);
951 
952  /* create new internal link */
953  bNodeSocket *input_sock = node_group_input_find_socket(input_node, iosock->identifier);
954  nodeAddLink(ngroup, input_node, input_sock, node, sock);
955  }
956 
957  LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
958  bool skip = false;
959  LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
960  if (link->fromsock == sock) {
961  skip = true;
962  }
963  }
964  if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
965  skip = true;
966  }
967  if (skip) {
968  continue;
969  }
970 
971  bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
972 
973  node_group_output_update(ngroup, output_node);
974 
975  /* create new internal link */
976  bNodeSocket *output_sock = node_group_output_find_socket(output_node,
977  iosock->identifier);
978  nodeAddLink(ngroup, node, sock, output_node, output_sock);
979  }
980  }
981  }
982  }
983 
984  /* update of the group tree */
986  /* update of the tree containing the group instance node */
988 }
989 
991  bNodeTree *ntree,
992  const char *ntype,
993  const char *ntreetype)
994 {
995  Main *bmain = CTX_data_main(C);
996 
997  float min[2], max[2];
998  const int totselect = node_get_selected_minmax(ntree, NULL, min, max, false);
999  /* don't make empty group */
1000  if (totselect == 0) {
1001  return NULL;
1002  }
1003 
1004  /* new nodetree */
1005  bNodeTree *ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
1006 
1007  /* make group node */
1008  bNode *gnode = nodeAddNode(C, ntree, ntype);
1009  gnode->id = (ID *)ngroup;
1010 
1011  gnode->locx = 0.5f * (min[0] + max[0]);
1012  gnode->locy = 0.5f * (min[1] + max[1]);
1013 
1015 
1016  /* update of the tree containing the group instance node */
1018 
1019  return gnode;
1020 }
1021 
1023 {
1024  SpaceNode *snode = CTX_wm_space_node(C);
1025  bNodeTree *ntree = snode->edittree;
1026  const char *ntree_idname = group_ntree_idname(C);
1027  const char *node_idname = node_group_idname(C);
1028  Main *bmain = CTX_data_main(C);
1029 
1031 
1032  if (!node_group_make_test_selected(ntree, NULL, ntree_idname, op->reports)) {
1033  return OPERATOR_CANCELLED;
1034  }
1035 
1036  bNode *gnode = node_group_make_from_selected(C, ntree, node_idname, ntree_idname);
1037 
1038  if (gnode) {
1039  bNodeTree *ngroup = (bNodeTree *)gnode->id;
1040 
1041  nodeSetActive(ntree, gnode);
1042  if (ngroup) {
1043  ED_node_tree_push(snode, ngroup, gnode);
1044  LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
1046  }
1047  ntreeUpdateTree(bmain, ngroup);
1048  }
1049  }
1050 
1051  ntreeUpdateTree(bmain, ntree);
1052 
1053  snode_notify(C, snode);
1054  snode_dag_update(C, snode);
1055 
1056  /* We broke relations in node tree, need to rebuild them in the graphs. */
1057  DEG_relations_tag_update(bmain);
1058 
1059  return OPERATOR_FINISHED;
1060 }
1061 
1063 {
1064  /* identifiers */
1065  ot->name = "Make Group";
1066  ot->description = "Make group from selected nodes";
1067  ot->idname = "NODE_OT_group_make";
1068 
1069  /* api callbacks */
1072 
1073  /* flags */
1075 }
1076 
1079 /* -------------------------------------------------------------------- */
1084 {
1085  SpaceNode *snode = CTX_wm_space_node(C);
1086  bNodeTree *ntree = snode->edittree;
1087  const char *node_idname = node_group_idname(C);
1088  Main *bmain = CTX_data_main(C);
1089 
1091 
1092  bNode *gnode = node_group_get_active(C, node_idname);
1093 
1094  if (!gnode || !gnode->id) {
1095  return OPERATOR_CANCELLED;
1096  }
1097 
1098  bNodeTree *ngroup = (bNodeTree *)gnode->id;
1099  if (!node_group_make_test_selected(ntree, gnode, ngroup->idname, op->reports)) {
1100  return OPERATOR_CANCELLED;
1101  }
1102 
1104 
1105  nodeSetActive(ntree, gnode);
1106  ED_node_tree_push(snode, ngroup, gnode);
1107  ntreeUpdateTree(bmain, ngroup);
1108 
1109  ntreeUpdateTree(bmain, ntree);
1110 
1111  snode_notify(C, snode);
1112  snode_dag_update(C, snode);
1113 
1114  return OPERATOR_FINISHED;
1115 }
1116 
1118 {
1119  /* identifiers */
1120  ot->name = "Group Insert";
1121  ot->description = "Insert selected nodes into a node group";
1122  ot->idname = "NODE_OT_group_insert";
1123 
1124  /* api callbacks */
1127 
1128  /* flags */
1130 }
1131 
Blender kernel action and pose functionality.
void BKE_animdata_transfer_by_basepath(struct Main *bmain, struct ID *srcID, struct ID *dstID, struct ListBase *basepaths)
Definition: anim_data.c:656
struct SpaceNode * CTX_wm_space_node(const bContext *C)
Definition: context.c:854
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct ID * BKE_id_copy(struct Main *bmain, const struct ID *id)
@ LIB_ID_COPY_DEFAULT
Definition: BKE_lib_id.h:139
void BKE_id_free(struct Main *bmain, void *idv)
void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node)
Definition: node.cc:1985
void ntreeFreeCache(struct bNodeTree *ntree)
Definition: node.cc:3039
void ntreeFreeTree(struct bNodeTree *ntree)
Definition: node.cc:3015
struct bNode * nodeGetActive(struct bNodeTree *ntree)
Definition: node.cc:3561
void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link)
Definition: node.cc:2231
struct bNodeSocket * ntreeAddSocketInterfaceFromSocket(struct bNodeTree *ntree, struct bNode *from_node, struct bNodeSocket *from_sock)
Definition: node.cc:3337
void nodeRemoveNode(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node, bool do_id_user)
Definition: node.cc:2932
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree)
Definition: node.cc:4262
struct bNode * BKE_node_copy_store_new_pointers(struct bNodeTree *ntree, struct bNode *node_src, const int flag)
Definition: node.cc:2155
struct bNodeLink * nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock)
Definition: node.cc:2189
struct bNode * nodeAddNode(const struct bContext *C, struct bNodeTree *ntree, const char *idname)
Definition: node.cc:1991
void nodeSetSelected(struct bNode *node, bool select)
Definition: node.cc:3664
struct bNodeTree * ntreeCopyTree_ex_new_pointers(const struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user)
struct bNodeTree * ntreeAddTree(struct Main *bmain, const char *name, const char *idname)
Definition: node.cc:2529
struct bNode * nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type)
Definition: node.cc:2004
#define NODE_GROUP_INPUT
Definition: BKE_node.h:874
void nodeToView(const struct bNode *node, float x, float y, float *rx, float *ry)
void nodeDetachNode(struct bNode *node)
Definition: node.cc:2462
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node)
Definition: node.cc:3694
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
MINLINE void mul_v2_fl(float r[2], float f)
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:1043
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
#define STR_ELEM(...)
Definition: BLI_string.h:218
#define INIT_MINMAX2(min, max)
#define UNUSED(x)
#define ELEM(...)
#define AT
#define STREQ(a, b)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
void DEG_relations_tag_update(struct Main *bmain)
#define NODE_DO_OUTPUT
@ SOCK_HIDDEN
@ SOCK_UNAVAIL
#define NODE_SELECT
@ NTREE_UPDATE
@ NTREE_UPDATE_LINKS
@ NTREE_UPDATE_NODES
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
bool ED_node_is_compositor(struct SpaceNode *snode)
Definition: node_edit.c:449
bool ED_node_is_texture(struct SpaceNode *snode)
Definition: node_edit.c:459
void ED_node_tree_push(struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *gnode)
Definition: space_node.c:100
bool ED_node_is_geometry(struct SpaceNode *snode)
Definition: node_edit.c:464
bool ED_node_is_shader(struct SpaceNode *snode)
Definition: node_edit.c:454
struct bNodeTree * ED_node_tree_get(struct SpaceNode *snode, int level)
Definition: space_node.c:162
void ED_node_tree_pop(struct SpaceNode *snode)
Definition: space_node.c:135
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain)
bool ED_operator_node_active(struct bContext *C)
Definition: screen_ops.c:292
bool ED_operator_node_editable(struct bContext *C)
Definition: screen_ops.c:303
NSNotificationCenter * center
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
NODE_GROUP_OUTPUT
StructRNA RNA_Node
#define C
Definition: RandGen.cpp:39
void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int icon, const char *propname, int value)
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:204
#define NC_SCENE
Definition: WM_types.h:279
#define ND_NODES
Definition: WM_types.h:336
OperationNode * node
bNodeTree * ntree
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
bNodeSocket * node_group_output_find_socket(bNode *node, const char *identifier)
Definition: node_common.c:530
void node_group_update(struct bNodeTree *ntree, struct bNode *node)
Definition: node_common.c:187
void node_group_input_update(bNodeTree *ntree, bNode *node)
Definition: node_common.c:444
bNodeSocket * node_group_find_output_socket(bNode *groupnode, const char *identifier)
Definition: node_common.c:65
bNodeSocket * node_group_input_find_socket(bNode *node, const char *identifier)
Definition: node_common.c:433
bNodeSocket * node_group_find_input_socket(bNode *groupnode, const char *identifier)
Definition: node_common.c:54
void node_group_output_update(bNodeTree *ntree, bNode *node)
Definition: node_common.c:541
void snode_dag_update(bContext *C, SpaceNode *snode)
Definition: node_edit.c:393
void snode_notify(bContext *C, SpaceNode *snode)
Definition: node_edit.c:411
static AnimationBasePathChange * animation_basepath_change_new(const char *src_basepath, const char *dst_basepath)
Definition: node_group.c:200
static int node_get_selected_minmax(bNodeTree *ntree, bNode *gnode, float *min, float *max, bool use_size)
Definition: node_group.c:728
const char * node_group_idname(bContext *C)
Definition: node_group.c:110
static const char * group_ntree_idname(bContext *C)
Definition: node_group.c:104
static int node_group_edit_exec(bContext *C, wmOperator *op)
Definition: node_group.c:147
static bool node_group_make_use_node(bNode *node, bNode *gnode)
Definition: node_group.c:663
static int node_group_insert_exec(bContext *C, wmOperator *op)
Definition: node_group.c:1083
static bNode * node_group_get_active(bContext *C, const char *node_idname)
Definition: node_group.c:130
static const EnumPropertyItem node_group_separate_types[]
Definition: node_group.c:571
static int node_group_make_exec(bContext *C, wmOperator *op)
Definition: node_group.c:1022
static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, bNode *gnode)
Definition: node_group.c:756
eNodeGroupSeparateType
Definition: node_group.c:565
@ NODE_GS_MOVE
Definition: node_group.c:567
@ NODE_GS_COPY
Definition: node_group.c:566
static void animation_basepath_change_free(AnimationBasePathChange *basepath_change)
Definition: node_group.c:209
static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
Definition: node_group.c:622
static bNode * node_group_make_from_selected(const bContext *C, bNodeTree *ntree, const char *ntype, const char *ntreetype)
Definition: node_group.c:990
static int node_group_ungroup_exec(bContext *C, wmOperator *op)
Definition: node_group.c:399
static bool node_group_operator_editable(bContext *C)
Definition: node_group.c:87
static bool node_group_operator_active_poll(bContext *C)
Definition: node_group.c:67
static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
Definition: node_group.c:219
static bool node_group_make_test_selected(bNodeTree *ntree, bNode *gnode, const char *ntree_idname, struct ReportList *reports)
Definition: node_group.c:669
void NODE_OT_group_insert(wmOperatorType *ot)
Definition: node_group.c:1117
static int node_group_separate_exec(bContext *C, wmOperator *op)
Definition: node_group.c:577
void NODE_OT_group_make(wmOperatorType *ot)
Definition: node_group.c:1062
static int node_group_separate_selected(Main *bmain, bNodeTree *ntree, bNodeTree *ngroup, float offx, float offy, int make_copy)
Definition: node_group.c:448
void NODE_OT_group_ungroup(wmOperatorType *ot)
Definition: node_group.c:426
void NODE_OT_group_separate(wmOperatorType *ot)
Definition: node_group.c:639
void NODE_OT_group_edit(wmOperatorType *ot)
Definition: node_group.c:173
void space_node_group_offset(struct SpaceNode *snode, float *x, float *y)
Definition: space_node.c:233
void sort_multi_input_socket_links(struct SpaceNode *snode, struct bNode *node, struct bNodeLink *drag_link, float cursor[2])
void node_socket_skip_reroutes(ListBase *links, bNode *node, bNodeSocket *socket, bNode **r_node, bNodeSocket **r_socket)
Definition: node_socket.cc:383
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
char * RNA_path_from_ID_to_struct(PointerRNA *ptr)
Definition: rna_access.c:5876
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
#define min(a, b)
Definition: sort.c:51
const char * dst_basepath
Definition: BKE_animsys.h:176
const char * src_basepath
Definition: BKE_animsys.h:175
Definition: DNA_ID.h:273
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
char tree_idname[64]
struct bNodeTree * edittree
struct bNodeTree * nodetree
char identifier[64]
char idname[64]
ListBase nodes
ListBase links
struct AnimData * adt
float locy
struct ID * id
struct bNode * parent
float locx
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
struct PointerRNA * ptr
float max
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156