4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2005 Blender Foundation.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Nathan Letwory
27 * ***** END GPL LICENSE BLOCK *****
30 /** \file blender/editors/space_node/node_edit.c
41 #include "MEM_guardedalloc.h"
44 #include "DNA_lamp_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_node_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_particle_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_world_types.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_storage_types.h"
55 #include "BLI_utildefines.h"
57 #include "BKE_context.h"
58 #include "BKE_depsgraph.h"
59 #include "BKE_global.h"
60 #include "BKE_image.h"
61 #include "BKE_library.h"
64 #include "BKE_material.h"
65 #include "BKE_modifier.h"
66 #include "BKE_paint.h"
67 #include "BKE_screen.h"
68 #include "BKE_texture.h"
69 #include "BKE_report.h"
73 #include "BLI_blenlib.h"
74 #include "BLI_storage_types.h"
76 #include "RE_pipeline.h"
78 #include "IMB_imbuf_types.h"
81 #include "ED_screen.h"
82 #include "ED_space_api.h"
83 #include "ED_render.h"
85 #include "RNA_access.h"
86 #include "RNA_define.h"
87 #include "RNA_enum_types.h"
92 #include "UI_interface.h"
93 #include "UI_resources.h"
94 #include "UI_view2d.h"
96 #include "IMB_imbuf.h"
98 #include "RNA_enum_types.h"
100 #include "GPU_material.h"
102 #include "node_intern.h"
104 static EnumPropertyItem socket_in_out_items[] = {
105 { SOCK_IN, "SOCK_IN", 0, "Input", "" },
106 { SOCK_OUT, "SOCK_OUT", 0, "Output", "" },
107 { 0, NULL, 0, NULL, NULL },
110 /* ***************** composite job manager ********************** */
112 typedef struct CompoJob {
115 bNodeTree *localtree;
121 /* called by compo, only to check job 'stop' value */
122 static int compo_breakjob(void *cjv)
129 /* called by compo, wmJob sends notifier */
130 static void compo_redrawjob(void *cjv, char *UNUSED(str))
137 static void compo_freejob(void *cjv)
142 ntreeLocalMerge(cj->localtree, cj->ntree);
147 /* only now we copy the nodetree, so adding many jobs while
148 sliding buttons doesn't frustrate */
149 static void compo_initjob(void *cjv)
153 cj->localtree= ntreeLocalize(cj->ntree);
156 /* called before redraw notifiers, it moves finished previews over */
157 static void compo_updatejob(void *cjv)
161 ntreeLocalSync(cj->localtree, cj->ntree);
164 static void compo_progressjob(void *cjv, float progress)
168 *(cj->progress) = progress;
172 /* only this runs inside thread */
173 static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
176 bNodeTree *ntree= cj->localtree;
178 if(cj->scene->use_nodes==0)
182 cj->do_update= do_update;
183 cj->progress= progress;
185 ntree->test_break= compo_breakjob;
187 ntree->stats_draw= compo_redrawjob;
189 ntree->progress= compo_progressjob;
192 // XXX BIF_store_spare();
194 ntreeCompositExecTree(ntree, &cj->scene->r, 1); /* 1 is do_previews */
196 ntree->test_break= NULL;
197 ntree->stats_draw= NULL;
198 ntree->progress= NULL;
202 void snode_composite_job(const bContext *C, ScrArea *sa)
204 SpaceNode *snode= sa->spacedata.first;
208 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Compositing", WM_JOB_EXCL_RENDER|WM_JOB_PROGRESS);
209 cj= MEM_callocN(sizeof(CompoJob), "compo job");
211 /* customdata for preview thread */
212 cj->scene= CTX_data_scene(C);
213 cj->ntree= snode->nodetree;
216 WM_jobs_customdata(steve, cj, compo_freejob);
217 WM_jobs_timer(steve, 0.1, NC_SCENE, NC_SCENE|ND_COMPO_RESULT);
218 WM_jobs_callbacks(steve, compo_startjob, compo_initjob, compo_updatejob, NULL);
220 WM_jobs_start(CTX_wm_manager(C), steve);
224 /* ***************************************** */
226 /* operator poll callback */
227 static int composite_node_active(bContext *C)
229 if( ED_operator_node_active(C)) {
230 SpaceNode *snode= CTX_wm_space_node(C);
231 if(snode->treetype==NTREE_COMPOSIT)
237 /* also checks for edited groups */
238 static bNode *editnode_get_active(bNodeTree *ntree)
242 /* check for edited group */
243 for(node= ntree->nodes.first; node; node= node->next)
244 if(nodeGroupEditGet(node))
247 return nodeGetActive((bNodeTree *)node->id);
249 return nodeGetActive(ntree);
252 void snode_dag_update(bContext *UNUSED(C), SpaceNode *snode)
254 DAG_id_tag_update(snode->id, 0);
257 void snode_notify(bContext *C, SpaceNode *snode)
259 WM_event_add_notifier(C, NC_NODE|NA_EDITED, NULL);
261 if(snode->treetype==NTREE_SHADER)
262 WM_event_add_notifier(C, NC_MATERIAL|ND_NODES, snode->id);
263 else if(snode->treetype==NTREE_COMPOSIT)
264 WM_event_add_notifier(C, NC_SCENE|ND_NODES, snode->id);
265 else if(snode->treetype==NTREE_TEXTURE)
266 WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id);
269 bNode *node_tree_get_editgroup(bNodeTree *nodetree)
273 /* get the groupnode */
274 for(gnode= nodetree->nodes.first; gnode; gnode= gnode->next)
275 if(nodeGroupEditGet(gnode))
280 /* assumes nothing being done in ntree yet, sets the default in/out node */
281 /* called from shading buttons or header */
282 void ED_node_shader_default(ID *id)
285 bNodeSocket *fromsock, *tosock;
288 int output_type, shader_type;
290 ntree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, 0);
292 switch(GS(id->name)) {
294 ((Material*)id)->nodetree = ntree;
295 output_type = SH_NODE_OUTPUT_MATERIAL;
296 shader_type = SH_NODE_BSDF_DIFFUSE;
299 ((World*)id)->nodetree = ntree;
300 output_type = SH_NODE_OUTPUT_WORLD;
301 shader_type = SH_NODE_BACKGROUND;
304 ((Lamp*)id)->nodetree = ntree;
305 output_type = SH_NODE_OUTPUT_LAMP;
306 shader_type = SH_NODE_EMISSION;
309 ((Tex*)id)->nodetree = ntree;
310 output_type = SH_NODE_OUTPUT_TEXTURE;
311 shader_type = SH_NODE_TEX_CLOUDS;
314 printf("ED_node_shader_default called on wrong ID type.\n");
318 ntemp.type = output_type;
319 out= nodeAddNode(ntree, &ntemp);
320 out->locx= 300.0f; out->locy= 300.0f;
322 ntemp.type = shader_type;
323 in= nodeAddNode(ntree, &ntemp);
324 in->locx= 10.0f; in->locy= 300.0f;
325 nodeSetActive(ntree, in);
327 /* only a link from color to color */
328 fromsock= in->outputs.first;
329 tosock= out->inputs.first;
330 nodeAddLink(ntree, in, fromsock, out, tosock);
332 ntreeUpdateTree(ntree);
335 /* assumes nothing being done in ntree yet, sets the default in/out node */
336 /* called from shading buttons or header */
337 void ED_node_composit_default(Scene *sce)
340 bNodeSocket *fromsock, *tosock;
343 /* but lets check it anyway */
346 printf("error in composite initialize\n");
350 sce->nodetree= ntreeAddTree("Compositing Nodetree", NTREE_COMPOSIT, 0);
352 ntemp.type = CMP_NODE_COMPOSITE;
353 out= nodeAddNode(sce->nodetree, &ntemp);
354 out->locx= 300.0f; out->locy= 400.0f;
358 ntemp.type = CMP_NODE_R_LAYERS;
359 in= nodeAddNode(sce->nodetree, &ntemp);
360 in->locx= 10.0f; in->locy= 400.0f;
363 nodeSetActive(sce->nodetree, in);
365 /* links from color to color */
366 fromsock= in->outputs.first;
367 tosock= out->inputs.first;
368 nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
370 ntreeUpdateTree(sce->nodetree);
372 // XXX ntreeCompositForceHidden(sce->nodetree);
375 /* assumes nothing being done in ntree yet, sets the default in/out node */
376 /* called from shading buttons or header */
377 void ED_node_texture_default(Tex *tx)
379 ED_node_shader_default(&tx->id);
383 bNodeSocket *fromsock, *tosock;
386 /* but lets check it anyway */
389 printf("error in texture initialize\n");
393 tx->nodetree= ntreeAddTree("Texture Nodetree", NTREE_TEXTURE, 0);
395 ntemp.type = TEX_NODE_OUTPUT;
396 out= nodeAddNode(tx->nodetree, &ntemp);
397 out->locx= 300.0f; out->locy= 300.0f;
399 ntemp.type = TEX_NODE_CHECKER;
400 in= nodeAddNode(tx->nodetree, &ntemp);
401 in->locx= 10.0f; in->locy= 300.0f;
402 nodeSetActive(tx->nodetree, in);
404 fromsock= in->outputs.first;
405 tosock= out->inputs.first;
406 nodeAddLink(tx->nodetree, in, fromsock, out, tosock);
408 ntreeUpdateTree(tx->nodetree);
412 /* id is supposed to contain a node tree */
413 void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype)
417 short idtype= GS(id->name);
419 if(idtype == ID_NT) {
420 *ntree= (bNodeTree*)id;
421 if(treetype) *treetype= (*ntree)->type;
423 else if(idtype == ID_MA) {
424 *ntree= ((Material*)id)->nodetree;
425 if(treetype) *treetype= NTREE_SHADER;
427 else if(idtype == ID_LA) {
428 *ntree= ((Lamp*)id)->nodetree;
429 if(treetype) *treetype= NTREE_SHADER;
431 else if(idtype == ID_WO) {
432 *ntree= ((World*)id)->nodetree;
433 if(treetype) *treetype= NTREE_SHADER;
435 else if(idtype == ID_SCE) {
436 *ntree= ((Scene*)id)->nodetree;
437 if(treetype) *treetype= NTREE_COMPOSIT;
439 else if(idtype == ID_TE) {
440 *ntree= ((Tex*)id)->nodetree;
441 if(treetype) *treetype= (*ntree)? (*ntree)->type: NTREE_SHADER;
444 if(treetype) *treetype= 0;
448 /* find editable group */
451 for(node= (*ntree)->nodes.first; node; node= node->next)
452 if(nodeGroupEditGet(node))
456 *edittree= (bNodeTree *)node->id;
463 if(treetype) *treetype= 0;
467 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
468 void snode_set_context(SpaceNode *snode, Scene *scene)
472 snode->id= snode->from= NULL;
474 if(snode->treetype==NTREE_SHADER) {
475 /* need active object, or we allow pinning... */
476 if(snode->shaderfrom == SNODE_SHADER_OBJECT) {
478 if(ob->type == OB_LAMP) {
479 snode->from= &ob->id;
483 Material *ma= give_current_material(ob, ob->actcol);
485 snode->from= &ob->id;
491 else { /* SNODE_SHADER_WORLD */
494 snode->id= &scene->world->id;
498 else if(snode->treetype==NTREE_COMPOSIT) {
499 snode->id= &scene->id;
501 /* update output sockets based on available layers */
502 ntreeCompositForceHidden(scene->nodetree, scene);
504 else if(snode->treetype==NTREE_TEXTURE) {
507 if(snode->texfrom==SNODE_TEX_OBJECT) {
509 tx= give_current_object_texture(ob);
511 if(ob->type == OB_LAMP)
512 snode->from= (ID*)ob->data;
514 snode->from= (ID*)give_current_material(ob, ob->actcol);
516 /* from is not set fully for material nodes, should be ID + Node then */
520 else if(snode->texfrom==SNODE_TEX_WORLD) {
521 tx= give_current_world_texture(scene->world);
522 snode->from= (ID *)scene->world;
526 struct Brush *brush= NULL;
528 if(ob && (ob->mode & OB_MODE_SCULPT))
529 brush= paint_brush(&scene->toolsettings->sculpt->paint);
531 brush= paint_brush(&scene->toolsettings->imapaint.paint);
534 snode->from= (ID *)brush;
535 tx= give_current_brush_texture(brush);
541 if (snode->nodetree && snode->nodetree->type == snode->treetype)
542 snode->id = &snode->nodetree->id;
547 node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL);
550 static void snode_tag_changed(SpaceNode *snode, bNode *node)
555 NodeTagChanged(snode->edittree, node);
557 /* if inside group, tag entire group */
558 gnode= node_tree_get_editgroup(snode->nodetree);
560 NodeTagIDChanged(snode->nodetree, gnode->id);
563 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
570 for(node=ntree->nodes.first; node; node=node->next)
571 if(node->type == NODE_GROUP && node->id)
572 if(has_nodetree((bNodeTree*)node->id, lookup))
578 void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
580 int was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE);
582 nodeSetActive(ntree, node);
584 if(node->type!=NODE_GROUP) {
585 int was_output= (node->flag & NODE_DO_OUTPUT);
587 /* tree specific activate calls */
588 if(ntree->type==NTREE_SHADER) {
589 /* when we select a material, active texture is cleared, for buttons */
590 if(node->id && ELEM3(GS(node->id->name), ID_MA, ID_LA, ID_WO))
591 nodeClearActiveID(ntree, ID_TE);
593 if(node->type==SH_NODE_OUTPUT) {
596 for(tnode= ntree->nodes.first; tnode; tnode= tnode->next)
597 if( tnode->type==SH_NODE_OUTPUT)
598 tnode->flag &= ~NODE_DO_OUTPUT;
600 node->flag |= NODE_DO_OUTPUT;
602 ED_node_generic_update(bmain, ntree, node);
605 /* if active texture changed, free glsl materials */
606 if((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
609 for(ma=bmain->mat.first; ma; ma=ma->id.next)
610 if(ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree))
611 GPU_material_free(ma);
614 WM_main_add_notifier(NC_MATERIAL|ND_NODES, node->id);
616 else if(ntree->type==NTREE_COMPOSIT) {
617 /* make active viewer, currently only 1 supported... */
618 if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
622 for(tnode= ntree->nodes.first; tnode; tnode= tnode->next)
623 if( ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
624 tnode->flag &= ~NODE_DO_OUTPUT;
626 node->flag |= NODE_DO_OUTPUT;
628 ED_node_generic_update(bmain, ntree, node);
630 /* addnode() doesnt link this yet... */
631 node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
633 else if(node->type==CMP_NODE_R_LAYERS) {
636 for(scene=bmain->scene.first; scene; scene=scene->id.next) {
637 if(scene->nodetree && scene->use_nodes && has_nodetree(scene->nodetree, ntree)) {
638 if(node->id==NULL || node->id==(ID *)scene) {
639 scene->r.actlay= node->custom1;
644 else if(node->type==CMP_NODE_COMPOSITE) {
648 for(tnode= ntree->nodes.first; tnode; tnode= tnode->next)
649 if( tnode->type==CMP_NODE_COMPOSITE)
650 tnode->flag &= ~NODE_DO_OUTPUT;
652 node->flag |= NODE_DO_OUTPUT;
653 ED_node_generic_update(bmain, ntree, node);
657 else if(ntree->type==NTREE_TEXTURE) {
661 ; // XXX BIF_preview_changed(-1);
662 // allqueue(REDRAWBUTSSHADING, 1);
663 // allqueue(REDRAWIPO, 0);
669 static int compare_nodes(bNode *a, bNode *b)
672 /* These tell if either the node or any of the parent nodes is selected.
673 * A selected parent means an unselected node is also in foreground!
675 int a_select=(a->flag & NODE_SELECT), b_select=(b->flag & NODE_SELECT);
676 int a_active=(a->flag & NODE_ACTIVE), b_active=(b->flag & NODE_ACTIVE);
678 /* if one is an ancestor of the other */
679 /* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */
680 for (parent = a->parent; parent; parent=parent->parent) {
681 /* if b is an ancestor, it is always behind a */
684 /* any selected ancestor moves the node forward */
685 if (parent->flag & NODE_ACTIVE)
687 if (parent->flag & NODE_SELECT)
690 for (parent = b->parent; parent; parent=parent->parent) {
691 /* if a is an ancestor, it is always behind b */
694 /* any selected ancestor moves the node forward */
695 if (parent->flag & NODE_ACTIVE)
697 if (parent->flag & NODE_SELECT)
701 /* if one of the nodes is in the background and the other not */
702 if ((a->flag & NODE_BACKGROUND) && !(b->flag & NODE_BACKGROUND))
704 else if (!(a->flag & NODE_BACKGROUND) && (b->flag & NODE_BACKGROUND))
707 /* if one has a higher selection state (active > selected > nothing) */
708 if (!b_active && a_active)
710 else if (!b_select && (a_active || a_select))
715 /* Sorts nodes by selection: unselected nodes first, then selected,
716 * then the active node at the very end. Relative order is kept intact!
718 void node_sort(bNodeTree *ntree)
720 /* merge sort is the algorithm of choice here */
721 bNode *first_a, *first_b, *node_a, *node_b, *tmp;
722 int totnodes= BLI_countlist(&ntree->nodes);
726 while (k < totnodes) {
727 first_a = first_b = ntree->nodes.first;
730 /* setup first_b pointer */
731 for (b=0; b < k && first_b; ++b) {
732 first_b = first_b->next;
734 /* all batches merged? */
742 while (a < k && b < k && node_b) {
743 if (compare_nodes(node_a, node_b)==0) {
744 node_a = node_a->next;
749 node_b = node_b->next;
751 BLI_remlink(&ntree->nodes, tmp);
752 BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
756 /* setup first pointers for next batch */
759 /* all nodes sorted? */
762 first_b = first_b->next;
771 static int inside_rctf(rctf *bounds, rctf *rect)
773 return (bounds->xmin <= rect->xmin && bounds->xmax >= rect->xmax
774 && bounds->ymin <= rect->ymin && bounds->ymax >= rect->ymax);
777 static void node_frame_attach_nodes(bNodeTree *UNUSED(ntree), bNode *frame)
781 /* only check nodes on top of the frame for attaching */
782 for (node=frame->next; node; node=node->next) {
783 if (node->parent==frame) {
784 /* detach nodes that went outside the frame */
785 if (!inside_rctf(&frame->totr, &node->totr))
786 nodeDetachNode(node);
788 else if (node->flag & NODE_SELECT && node->parent==NULL) {
789 /* attach selected, still unparented nodes */
790 if (inside_rctf(&frame->totr, &node->totr))
791 nodeAttachNode(node, frame);
796 void ED_node_update_hierarchy(bContext *UNUSED(C), bNodeTree *ntree)
800 /* XXX This does not work due to layout functions relying on node->block,
801 * which only exists during actual drawing. Can we rely on valid totr rects?
803 /* make sure nodes have correct bounding boxes after transform */
804 // node_update_nodetree(C, ntree, 0.0f, 0.0f);
806 /* all selected nodes are re-parented */
807 for (node=ntree->nodes.last; node; node=node->prev) {
808 if (node->flag & NODE_SELECT && node->parent)
809 nodeDetachNode(node);
812 /* update higher Z-level nodes first */
813 for (node=ntree->nodes.last; node; node=node->prev) {
815 if (node->type==NODE_FRAME)
816 node_frame_attach_nodes(ntree, node);
820 /* ***************** generic operator functions for nodes ***************** */
822 static int edit_node_poll(bContext *C)
824 return ED_operator_node_active(C);
827 static void edit_node_properties(wmOperatorType *ot)
829 /* XXX could node be a context pointer? */
830 RNA_def_string(ot->srna, "node", "", 32, "Node", "");
831 RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET);
832 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Side", "");
835 static int edit_node_invoke_properties(bContext *C, wmOperator *op)
837 if (!RNA_property_is_set(op->ptr, "node")) {
838 bNode *node= CTX_data_pointer_get_type(C, "node", &RNA_Node).data;
842 RNA_string_set(op->ptr, "node", node->name);
845 if (!RNA_property_is_set(op->ptr, "in_out"))
846 RNA_enum_set(op->ptr, "in_out", SOCK_IN);
848 if (!RNA_property_is_set(op->ptr, "socket"))
849 RNA_int_set(op->ptr, "socket", 0);
854 static void edit_node_properties_get(wmOperator *op, bNodeTree *ntree, bNode **rnode, bNodeSocket **rsock, int *rin_out)
857 bNodeSocket *sock=NULL;
862 RNA_string_get(op->ptr, "node", nodename);
863 node = nodeFindNodebyName(ntree, nodename);
865 in_out = RNA_enum_get(op->ptr, "in_out");
867 sockindex = RNA_int_get(op->ptr, "socket");
869 case SOCK_IN: sock = BLI_findlink(&node->inputs, sockindex); break;
870 case SOCK_OUT: sock = BLI_findlink(&node->outputs, sockindex); break;
881 /* ***************** Edit Group operator ************* */
883 void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
887 /* make sure nothing has group editing on */
888 for(node=snode->nodetree->nodes.first; node; node=node->next)
889 nodeGroupEditClear(node);
892 /* with NULL argument we do a toggle */
893 if(snode->edittree==snode->nodetree)
894 gnode= nodeGetActive(snode->nodetree);
898 snode->edittree = nodeGroupEditSet(gnode, 1);
900 /* deselect all other nodes, so we can also do grabbing of entire subtree */
901 for(node= snode->nodetree->nodes.first; node; node= node->next)
902 node->flag &= ~SELECT;
903 gnode->flag |= SELECT;
906 snode->edittree= snode->nodetree;
909 static int node_group_edit_exec(bContext *C, wmOperator *UNUSED(op))
911 SpaceNode *snode = CTX_wm_space_node(C);
913 ED_preview_kill_jobs(C);
915 if (snode->nodetree==snode->edittree) {
916 bNode *gnode= nodeGetActive(snode->nodetree);
917 snode_make_group_editable(snode, gnode);
920 snode_make_group_editable(snode, NULL);
922 WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL);
924 return OPERATOR_FINISHED;
927 static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
929 SpaceNode *snode = CTX_wm_space_node(C);
932 gnode= nodeGetActive(snode->edittree);
934 if(gnode && gnode->id && GS(gnode->id->name)==ID_NT && gnode->id->lib) {
935 uiPupMenuOkee(C, op->type->idname, "Make group local?");
936 return OPERATOR_CANCELLED;
939 return node_group_edit_exec(C, op);
942 void NODE_OT_group_edit(wmOperatorType *ot)
945 ot->name = "Edit Group";
946 ot->description = "Edit node group";
947 ot->idname = "NODE_OT_group_edit";
950 ot->invoke = node_group_edit_invoke;
951 ot->exec = node_group_edit_exec;
952 ot->poll = ED_operator_node_active;
955 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
958 /* ***************** Add Group Socket operator ************* */
960 static int node_group_socket_add_exec(bContext *C, wmOperator *op)
962 SpaceNode *snode = CTX_wm_space_node(C);
965 int type= SOCK_FLOAT;
966 bNodeTree *ngroup= snode->edittree;
969 ED_preview_kill_jobs(C);
971 if (RNA_property_is_set(op->ptr, "name"))
972 RNA_string_get(op->ptr, "name", name);
974 if (RNA_property_is_set(op->ptr, "type"))
975 type = RNA_enum_get(op->ptr, "type");
977 if (RNA_property_is_set(op->ptr, "in_out"))
978 in_out = RNA_enum_get(op->ptr, "in_out");
980 return OPERATOR_CANCELLED;
982 /* using placeholder subtype first */
983 sock = node_group_add_socket(ngroup, name, type, in_out);
985 ntreeUpdateTree(ngroup);
987 snode_notify(C, snode);
989 return OPERATOR_FINISHED;
992 void NODE_OT_group_socket_add(wmOperatorType *ot)
995 ot->name = "Add Group Socket";
996 ot->description = "Add node group socket";
997 ot->idname = "NODE_OT_group_socket_add";
1000 ot->exec = node_group_socket_add_exec;
1001 ot->poll = ED_operator_node_active;
1004 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1006 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
1007 RNA_def_string(ot->srna, "name", "", 32, "Name", "Group socket name");
1008 RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_FLOAT, "Type", "Type of the group socket");
1011 /* ***************** Remove Group Socket operator ************* */
1013 static int node_group_socket_remove_exec(bContext *C, wmOperator *op)
1015 SpaceNode *snode = CTX_wm_space_node(C);
1018 bNodeTree *ngroup= snode->edittree;
1021 ED_preview_kill_jobs(C);
1023 if (RNA_property_is_set(op->ptr, "index"))
1024 index = RNA_int_get(op->ptr, "index");
1026 return OPERATOR_CANCELLED;
1028 if (RNA_property_is_set(op->ptr, "in_out"))
1029 in_out = RNA_enum_get(op->ptr, "in_out");
1031 return OPERATOR_CANCELLED;
1033 sock = (bNodeSocket*)BLI_findlink(in_out==SOCK_IN ? &ngroup->inputs : &ngroup->outputs, index);
1035 node_group_remove_socket(ngroup, sock, in_out);
1036 ntreeUpdateTree(ngroup);
1038 snode_notify(C, snode);
1041 return OPERATOR_FINISHED;
1044 void NODE_OT_group_socket_remove(wmOperatorType *ot)
1047 ot->name = "Remove Group Socket";
1048 ot->description = "Remove a node group socket";
1049 ot->idname = "NODE_OT_group_socket_remove";
1052 ot->exec = node_group_socket_remove_exec;
1053 ot->poll = ED_operator_node_active;
1056 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1058 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
1059 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
1062 /* ***************** Move Group Socket Up operator ************* */
1064 static int node_group_socket_move_up_exec(bContext *C, wmOperator *op)
1066 SpaceNode *snode = CTX_wm_space_node(C);
1069 bNodeTree *ngroup= snode->edittree;
1070 bNodeSocket *sock, *prev;
1072 ED_preview_kill_jobs(C);
1074 if (RNA_property_is_set(op->ptr, "index"))
1075 index = RNA_int_get(op->ptr, "index");
1077 return OPERATOR_CANCELLED;
1079 if (RNA_property_is_set(op->ptr, "in_out"))
1080 in_out = RNA_enum_get(op->ptr, "in_out");
1082 return OPERATOR_CANCELLED;
1085 if (in_out==SOCK_IN) {
1086 sock = (bNodeSocket*)BLI_findlink(&ngroup->inputs, index);
1088 /* can't move up the first socket */
1090 return OPERATOR_CANCELLED;
1091 BLI_remlink(&ngroup->inputs, sock);
1092 BLI_insertlinkbefore(&ngroup->inputs, prev, sock);
1094 ngroup->update |= NTREE_UPDATE_GROUP_IN;
1096 else if (in_out==SOCK_OUT) {
1097 sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index);
1099 /* can't move up the first socket */
1101 return OPERATOR_CANCELLED;
1102 BLI_remlink(&ngroup->outputs, sock);
1103 BLI_insertlinkbefore(&ngroup->outputs, prev, sock);
1105 ngroup->update |= NTREE_UPDATE_GROUP_OUT;
1107 ntreeUpdateTree(ngroup);
1109 snode_notify(C, snode);
1111 return OPERATOR_FINISHED;
1114 void NODE_OT_group_socket_move_up(wmOperatorType *ot)
1117 ot->name = "Move Group Socket Up";
1118 ot->description = "Move up node group socket";
1119 ot->idname = "NODE_OT_group_socket_move_up";
1122 ot->exec = node_group_socket_move_up_exec;
1123 ot->poll = ED_operator_node_active;
1126 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1128 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
1129 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
1132 /* ***************** Move Group Socket Up operator ************* */
1134 static int node_group_socket_move_down_exec(bContext *C, wmOperator *op)
1136 SpaceNode *snode = CTX_wm_space_node(C);
1139 bNodeTree *ngroup= snode->edittree;
1140 bNodeSocket *sock, *next;
1142 ED_preview_kill_jobs(C);
1144 if (RNA_property_is_set(op->ptr, "index"))
1145 index = RNA_int_get(op->ptr, "index");
1147 return OPERATOR_CANCELLED;
1149 if (RNA_property_is_set(op->ptr, "in_out"))
1150 in_out = RNA_enum_get(op->ptr, "in_out");
1152 return OPERATOR_CANCELLED;
1155 if (in_out==SOCK_IN) {
1156 sock = (bNodeSocket*)BLI_findlink(&ngroup->inputs, index);
1158 /* can't move down the last socket */
1160 return OPERATOR_CANCELLED;
1161 BLI_remlink(&ngroup->inputs, sock);
1162 BLI_insertlinkafter(&ngroup->inputs, next, sock);
1164 ngroup->update |= NTREE_UPDATE_GROUP_IN;
1166 else if (in_out==SOCK_OUT) {
1167 sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index);
1169 /* can't move down the last socket */
1171 return OPERATOR_CANCELLED;
1172 BLI_remlink(&ngroup->outputs, sock);
1173 BLI_insertlinkafter(&ngroup->outputs, next, sock);
1175 ngroup->update |= NTREE_UPDATE_GROUP_OUT;
1177 ntreeUpdateTree(ngroup);
1179 snode_notify(C, snode);
1181 return OPERATOR_FINISHED;
1184 void NODE_OT_group_socket_move_down(wmOperatorType *ot)
1187 ot->name = "Move Group Socket Down";
1188 ot->description = "Move down node group socket";
1189 ot->idname = "NODE_OT_group_socket_move_down";
1192 ot->exec = node_group_socket_move_down_exec;
1193 ot->poll = ED_operator_node_active;
1196 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1198 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
1199 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
1202 /* ******************** Ungroup operator ********************** */
1204 static int node_group_ungroup_exec(bContext *C, wmOperator *op)
1206 SpaceNode *snode = CTX_wm_space_node(C);
1209 ED_preview_kill_jobs(C);
1211 /* are we inside of a group? */
1212 gnode= node_tree_get_editgroup(snode->nodetree);
1214 snode_make_group_editable(snode, NULL);
1216 gnode= nodeGetActive(snode->edittree);
1218 return OPERATOR_CANCELLED;
1220 if(gnode->type!=NODE_GROUP) {
1221 BKE_report(op->reports, RPT_WARNING, "Not a group");
1222 return OPERATOR_CANCELLED;
1224 else if(!node_group_ungroup(snode->edittree, gnode)) {
1225 BKE_report(op->reports, RPT_WARNING, "Can't ungroup");
1226 return OPERATOR_CANCELLED;
1229 snode_notify(C, snode);
1230 snode_dag_update(C, snode);
1232 return OPERATOR_FINISHED;
1235 void NODE_OT_group_ungroup(wmOperatorType *ot)
1238 ot->name = "Ungroup";
1239 ot->description = "Ungroup selected nodes";
1240 ot->idname = "NODE_OT_group_ungroup";
1243 ot->exec = node_group_ungroup_exec;
1244 ot->poll = ED_operator_node_active;
1247 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1250 /* ************************** Node generic ************** */
1252 /* is rct in visible part of node? */
1253 static bNode *visible_node(SpaceNode *snode, rctf *rct)
1257 for(node=snode->edittree->nodes.last; node; node=node->prev) {
1258 if(BLI_isect_rctf(&node->totr, rct, NULL))
1264 /* **************************** */
1266 typedef struct NodeViewMove {
1268 int xmin, ymin, xmax, ymax;
1271 static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
1273 SpaceNode *snode= CTX_wm_space_node(C);
1274 ARegion *ar= CTX_wm_region(C);
1275 NodeViewMove *nvm= op->customdata;
1277 switch (event->type) {
1280 snode->xof -= (nvm->mvalo[0]-event->mval[0]);
1281 snode->yof -= (nvm->mvalo[1]-event->mval[1]);
1282 nvm->mvalo[0]= event->mval[0];
1283 nvm->mvalo[1]= event->mval[1];
1285 /* prevent dragging image outside of the window and losing it! */
1286 CLAMP(snode->xof, nvm->xmin, nvm->xmax);
1287 CLAMP(snode->yof, nvm->ymin, nvm->ymax);
1289 ED_region_tag_redraw(ar);
1298 op->customdata= NULL;
1300 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_NODE, NULL);
1302 return OPERATOR_FINISHED;
1305 return OPERATOR_RUNNING_MODAL;
1308 static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
1310 ARegion *ar= CTX_wm_region(C);
1317 ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
1318 ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock);
1321 BKE_image_release_ibuf(ima, lock);
1322 return OPERATOR_CANCELLED;
1325 nvm= MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct");
1326 op->customdata= nvm;
1327 nvm->mvalo[0]= event->mval[0];
1328 nvm->mvalo[1]= event->mval[1];
1330 nvm->xmin = -(ar->winx/2) - ibuf->x/2 + pad;
1331 nvm->xmax = ar->winx/2 + ibuf->x/2 - pad;
1332 nvm->ymin = -(ar->winy/2) - ibuf->y/2 + pad;
1333 nvm->ymax = ar->winy/2 + ibuf->y/2 - pad;
1335 BKE_image_release_ibuf(ima, lock);
1337 /* add modal handler */
1338 WM_event_add_modal_handler(C, op);
1340 return OPERATOR_RUNNING_MODAL;
1343 static int snode_bg_viewmove_cancel(bContext *UNUSED(C), wmOperator *op)
1345 MEM_freeN(op->customdata);
1346 op->customdata= NULL;
1348 return OPERATOR_CANCELLED;
1351 void NODE_OT_backimage_move(wmOperatorType *ot)
1354 ot->name= "Background Image Move";
1355 ot->description = "Move Node backdrop";
1356 ot->idname= "NODE_OT_backimage_move";
1359 ot->invoke= snode_bg_viewmove_invoke;
1360 ot->modal= snode_bg_viewmove_modal;
1361 ot->poll= composite_node_active;
1362 ot->cancel= snode_bg_viewmove_cancel;
1365 ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1368 static int backimage_zoom(bContext *C, wmOperator *op)
1370 SpaceNode *snode= CTX_wm_space_node(C);
1371 ARegion *ar= CTX_wm_region(C);
1372 float fac= RNA_float_get(op->ptr, "factor");
1375 ED_region_tag_redraw(ar);
1377 return OPERATOR_FINISHED;
1381 void NODE_OT_backimage_zoom(wmOperatorType *ot)
1385 ot->name= "Background Image Zoom";
1386 ot->idname= "NODE_OT_backimage_zoom";
1389 ot->exec= backimage_zoom;
1390 ot->poll= composite_node_active;
1393 ot->flag= OPTYPE_BLOCKING;
1396 RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f);
1399 /******************** sample backdrop operator ********************/
1401 typedef struct ImageSampleInfo {
1414 static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
1416 ImageSampleInfo *info= arg_info;
1418 draw_nodespace_color_info(ar, (CTX_data_scene(C)->r.color_mgt_flag & R_COLOR_MANAGEMENT), info->channels,
1419 info->x, info->y, info->col, info->colf);
1422 static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
1424 SpaceNode *snode= CTX_wm_space_node(C);
1425 ARegion *ar= CTX_wm_region(C);
1426 ImageSampleInfo *info= op->customdata;
1430 float fx, fy, bufx, bufy;
1432 ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
1433 ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock);
1438 if(info->color_manage)
1439 ibuf->profile = IB_PROFILE_LINEAR_RGB;
1441 ibuf->profile = IB_PROFILE_NONE;
1442 IMB_rect_from_float(ibuf);
1445 /* map the mouse coords to the backdrop image space */
1446 bufx = ibuf->x * snode->zoom;
1447 bufy = ibuf->y * snode->zoom;
1448 fx = (bufx > 0.0f ? ((float)event->mval[0] - 0.5f*ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
1449 fy = (bufy > 0.0f ? ((float)event->mval[1] - 0.5f*ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
1451 if(fx>=0.0f && fy>=0.0f && fx<1.0f && fy<1.0f) {
1454 int x= (int)(fx*ibuf->x), y= (int)(fy*ibuf->y);
1456 CLAMP(x, 0, ibuf->x-1);
1457 CLAMP(y, 0, ibuf->y-1);
1462 info->channels= ibuf->channels;
1465 cp= (char *)(ibuf->rect + y*ibuf->x + x);
1467 info->col[0]= cp[0];
1468 info->col[1]= cp[1];
1469 info->col[2]= cp[2];
1470 info->col[3]= cp[3];
1472 info->colf[0]= (float)cp[0]/255.0f;
1473 info->colf[1]= (float)cp[1]/255.0f;
1474 info->colf[2]= (float)cp[2]/255.0f;
1475 info->colf[3]= (float)cp[3]/255.0f;
1477 if(ibuf->rect_float) {
1478 fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
1480 info->colf[0]= fp[0];
1481 info->colf[1]= fp[1];
1482 info->colf[2]= fp[2];
1483 info->colf[3]= fp[3];
1489 BKE_image_release_ibuf(ima, lock);
1491 ED_area_tag_redraw(CTX_wm_area(C));
1494 static void sample_exit(bContext *C, wmOperator *op)
1496 ImageSampleInfo *info= op->customdata;
1498 ED_region_draw_cb_exit(info->art, info->draw_handle);
1499 ED_area_tag_redraw(CTX_wm_area(C));
1503 static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
1505 SpaceNode *snode= CTX_wm_space_node(C);
1506 ARegion *ar= CTX_wm_region(C);
1507 ImageSampleInfo *info;
1509 if(snode->treetype!=NTREE_COMPOSIT || !(snode->flag & SNODE_BACKDRAW))
1510 return OPERATOR_CANCELLED;
1512 info= MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
1513 info->art= ar->type;
1514 info->draw_handle = ED_region_draw_cb_activate(ar->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
1515 op->customdata= info;
1517 sample_apply(C, op, event);
1519 WM_event_add_modal_handler(C, op);
1521 return OPERATOR_RUNNING_MODAL;
1524 static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
1526 switch(event->type) {
1528 case RIGHTMOUSE: // XXX hardcoded
1530 return OPERATOR_CANCELLED;
1532 sample_apply(C, op, event);
1536 return OPERATOR_RUNNING_MODAL;
1539 static int sample_cancel(bContext *C, wmOperator *op)
1542 return OPERATOR_CANCELLED;
1545 void NODE_OT_backimage_sample(wmOperatorType *ot)
1548 ot->name= "Backimage Sample";
1549 ot->idname= "NODE_OT_backimage_sample";
1552 ot->invoke= sample_invoke;
1553 ot->modal= sample_modal;
1554 ot->cancel= sample_cancel;
1555 ot->poll= ED_operator_node_active;
1558 ot->flag= OPTYPE_BLOCKING;
1561 /* ********************** size widget operator ******************** */
1563 typedef struct NodeSizeWidget {
1564 float mxstart, mystart;
1565 float oldwidth, oldheight;
1569 static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
1571 SpaceNode *snode= CTX_wm_space_node(C);
1572 ARegion *ar= CTX_wm_region(C);
1573 bNode *node= editnode_get_active(snode->edittree);
1574 NodeSizeWidget *nsw= op->customdata;
1577 switch (event->type) {
1580 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
1584 if(node->flag & NODE_HIDDEN) {
1585 node->miniwidth= nsw->oldminiwidth + mx - nsw->mxstart;
1586 CLAMP(node->miniwidth, 0.0f, 100.0f);
1589 node->width= nsw->oldwidth + mx - nsw->mxstart;
1590 CLAMP(node->width, UI_DPI_FAC*node->typeinfo->minwidth, UI_DPI_FAC*node->typeinfo->maxwidth);
1592 /* height works the other way round ... */
1593 node->height= nsw->oldheight - my + nsw->mystart;
1594 CLAMP(node->height, node->typeinfo->minheight, node->typeinfo->maxheight);
1597 ED_region_tag_redraw(ar);
1606 op->customdata= NULL;
1608 ED_node_update_hierarchy(C, snode->edittree);
1610 return OPERATOR_FINISHED;
1613 return OPERATOR_RUNNING_MODAL;
1616 static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event)
1618 SpaceNode *snode= CTX_wm_space_node(C);
1619 ARegion *ar= CTX_wm_region(C);
1620 bNode *node= editnode_get_active(snode->edittree);
1623 /* convert mouse coordinates to v2d space */
1624 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
1625 &snode->mx, &snode->my);
1627 if(node->typeinfo->resize_area_func(node, snode->mx, snode->my)) {
1628 NodeSizeWidget *nsw= MEM_callocN(sizeof(NodeSizeWidget), "size widget op data");
1630 op->customdata= nsw;
1631 nsw->mxstart= snode->mx;
1632 nsw->mystart= snode->my;
1635 nsw->oldwidth= node->width;
1636 nsw->oldheight= node->height;
1637 nsw->oldminiwidth= node->miniwidth;
1639 /* add modal handler */
1640 WM_event_add_modal_handler(C, op);
1642 return OPERATOR_RUNNING_MODAL;
1645 return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
1648 static int node_resize_cancel(bContext *UNUSED(C), wmOperator *op)
1650 MEM_freeN(op->customdata);
1651 op->customdata= NULL;
1653 return OPERATOR_CANCELLED;
1656 void NODE_OT_resize(wmOperatorType *ot)
1659 ot->name= "Resize Node";
1660 ot->idname= "NODE_OT_resize";
1663 ot->invoke= node_resize_invoke;
1664 ot->modal= node_resize_modal;
1665 ot->poll= ED_operator_node_active;
1666 ot->cancel= node_resize_cancel;
1669 ot->flag= OPTYPE_BLOCKING;
1672 /* ********************** select ******************** */
1676 void node_deselectall(SpaceNode *snode)
1680 for(node= snode->edittree->nodes.first; node; node= node->next)
1681 node->flag &= ~SELECT;
1684 /* return 1 if we need redraw otherwise zero. */
1685 int node_select_same_type(SpaceNode *snode)
1690 /* search for the active node. */
1691 for (nac= snode->edittree->nodes.first; nac; nac= nac->next) {
1692 if (nac->flag & SELECT)
1696 /* no active node, return. */
1701 for (p= snode->edittree->nodes.first; p; p= p->next) {
1702 if (p->type != nac->type && p->flag & SELECT) {
1703 /* if it's selected but different type, unselect */
1707 else if (p->type == nac->type && (!(p->flag & SELECT))) {
1708 /* if it's the same type and is not selected, select! */
1716 /* return 1 if we need redraw, otherwise zero.
1717 * dir can be 0 == next or 0 != prev.
1719 int node_select_same_type_np(SpaceNode *snode, int dir)
1723 /* search the active one. */
1724 for (nac= snode->edittree->nodes.first; nac; nac= nac->next) {
1725 if (nac->flag & SELECT)
1729 /* no active node, return. */
1739 /* Now search the next with the same type. */
1740 if (p->type == nac->type)
1750 node_deselectall(snode);
1757 int node_has_hidden_sockets(bNode *node)
1761 for(sock= node->inputs.first; sock; sock= sock->next)
1762 if(sock->flag & SOCK_HIDDEN)
1764 for(sock= node->outputs.first; sock; sock= sock->next)
1765 if(sock->flag & SOCK_HIDDEN)
1770 static void node_link_viewer(SpaceNode *snode, bNode *tonode)
1775 if(tonode==NULL || tonode->outputs.first==NULL)
1777 if( ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
1781 for(node= snode->edittree->nodes.first; node; node= node->next)
1782 if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
1783 if(node->flag & NODE_DO_OUTPUT)
1785 /* no viewer, we make one active */
1787 for(node= snode->edittree->nodes.first; node; node= node->next) {
1788 if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
1789 node->flag |= NODE_DO_OUTPUT;
1797 bNodeSocket *sock= NULL;
1799 /* try to find an already connected socket to cycle to the next */
1800 for(link= snode->edittree->links.first; link; link= link->next)
1801 if(link->tonode==node && link->fromnode==tonode)
1802 if(link->tosock==node->inputs.first)
1806 /* unlink existing connection */
1807 sock= link->fromsock;
1808 nodeRemLink(snode->edittree, link);
1810 /* find a socket after the previously connected socket */
1811 for(sock=sock->next; sock; sock= sock->next)
1812 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
1816 /* find a socket starting from the first socket */
1818 for(sock= tonode->outputs.first; sock; sock= sock->next)
1819 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
1824 /* get link to viewer */
1825 for(link= snode->edittree->links.first; link; link= link->next)
1826 if(link->tonode==node && link->tosock==node->inputs.first)
1830 nodeAddLink(snode->edittree, tonode, sock, node, node->inputs.first);
1833 link->fromnode= tonode;
1834 link->fromsock= sock;
1836 ntreeUpdateTree(snode->edittree);
1837 snode_tag_changed(snode, node);
1843 static int node_active_link_viewer(bContext *C, wmOperator *UNUSED(op))
1845 SpaceNode *snode= CTX_wm_space_node(C);
1848 node= editnode_get_active(snode->edittree);
1851 return OPERATOR_CANCELLED;
1853 ED_preview_kill_jobs(C);
1855 node_link_viewer(snode, node);
1856 snode_notify(C, snode);
1858 return OPERATOR_FINISHED;
1863 void NODE_OT_link_viewer(wmOperatorType *ot)
1866 ot->name= "Link to Viewer Node";
1867 ot->description = "Link to Viewer Node";
1868 ot->idname= "NODE_OT_link_viewer";
1871 ot->exec= node_active_link_viewer;
1872 ot->poll= ED_operator_node_active;
1875 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1880 /* return 0, nothing done */
1881 static int UNUSED_FUNCTION(node_mouse_groupheader)(SpaceNode *snode)
1887 gnode= node_tree_get_editgroup(snode->nodetree);
1888 if(gnode==NULL) return 0;
1890 // XXX getmouseco_areawin(mval);
1891 // XXX areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1893 /* click in header or outside? */
1894 if(BLI_in_rctf(&gnode->totr, mx, my)==0) {
1895 rctf rect= gnode->totr;
1897 rect.ymax += NODE_DY;
1898 if(BLI_in_rctf(&rect, mx, my)==0)
1899 snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
1901 // XXX transform_nodes(snode->nodetree, 'g', "Move group");
1908 /* checks snode->mouse position, and returns found node/socket */
1909 /* type is SOCK_IN and/or SOCK_OUT */
1910 static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
1916 /* check if we click in a socket */
1917 for(node= snode->edittree->nodes.first; node; node= node->next) {
1919 rect.xmin = snode->mx - (NODE_SOCKSIZE+4);
1920 rect.ymin = snode->my - (NODE_SOCKSIZE+4);
1921 rect.xmax = snode->mx + (NODE_SOCKSIZE+4);
1922 rect.ymax = snode->my + (NODE_SOCKSIZE+4);
1924 if (!(node->flag & NODE_HIDDEN)) {
1925 /* extra padding inside and out - allow dragging on the text areas too */
1926 if (in_out == SOCK_IN) {
1927 rect.xmax += NODE_SOCKSIZE;
1928 rect.xmin -= NODE_SOCKSIZE*4;
1929 } else if (in_out == SOCK_OUT) {
1930 rect.xmax += NODE_SOCKSIZE*4;
1931 rect.xmin -= NODE_SOCKSIZE;
1935 if(in_out & SOCK_IN) {
1936 for(sock= node->inputs.first; sock; sock= sock->next) {
1937 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
1938 if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1939 if(node == visible_node(snode, &rect)) {
1948 if(in_out & SOCK_OUT) {
1949 for(sock= node->outputs.first; sock; sock= sock->next) {
1950 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
1951 if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1952 if(node == visible_node(snode, &rect)) {
1963 /* check group sockets
1964 * NB: using ngroup->outputs as input sockets and vice versa here!
1966 if(in_out & SOCK_IN) {
1967 for(sock= snode->edittree->outputs.first; sock; sock= sock->next) {
1968 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
1969 if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1970 *nodep= NULL; /* NULL node pointer indicates group socket */
1977 if(in_out & SOCK_OUT) {
1978 for(sock= snode->edittree->inputs.first; sock; sock= sock->next) {
1979 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
1980 if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1981 *nodep= NULL; /* NULL node pointer indicates group socket */
1992 static int node_socket_hilights(SpaceNode *snode, int in_out)
1995 bNodeSocket *sock, *tsock, *socksel= NULL;
1998 if(snode->edittree==NULL) return 0;
2000 /* deselect sockets */
2001 for(node= snode->edittree->nodes.first; node; node= node->next) {
2002 for(sock= node->inputs.first; sock; sock= sock->next) {
2003 if(sock->flag & SELECT) {
2004 sock->flag &= ~SELECT;
2009 for(sock= node->outputs.first; sock; sock= sock->next) {
2010 if(sock->flag & SELECT) {
2011 sock->flag &= ~SELECT;
2018 // XXX mousepos should be set here!
2020 if(find_indicated_socket(snode, &node, &tsock, in_out)) {
2021 tsock->flag |= SELECT;
2022 if(redraw==1 && tsock==socksel) redraw= 0;
2029 static int outside_group_rect(SpaceNode *snode)
2031 bNode *gnode= node_tree_get_editgroup(snode->nodetree);
2033 return (snode->mx < gnode->totr.xmin || snode->mx >= gnode->totr.xmax
2034 || snode->my < gnode->totr.ymin || snode->my >= gnode->totr.ymax);
2039 /* ****************** Add *********************** */
2042 typedef struct bNodeListItem {
2043 struct bNodeListItem *next, *prev;
2047 static int sort_nodes_locx(void *a, void *b)
2049 bNodeListItem *nli1 = (bNodeListItem *)a;
2050 bNodeListItem *nli2 = (bNodeListItem *)b;
2051 bNode *node1 = nli1->node;
2052 bNode *node2 = nli2->node;
2054 if (node1->locx > node2->locx)
2060 static int socket_is_available(bNodeTree *ntree, bNodeSocket *sock, int allow_used)
2062 if (sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
2066 if (nodeCountSocketLinks(ntree, sock) > 0)
2072 static bNodeSocket *best_socket_output(bNodeTree *ntree, bNode *node, bNodeSocket *sock_target, int allow_multiple)
2076 /* first try to find a socket with a matching name */
2077 for (sock=node->outputs.first; sock; sock=sock->next) {
2079 if (!socket_is_available(ntree, sock, allow_multiple))
2082 /* check for same types */
2083 if (sock->type == sock_target->type) {
2084 if (strcmp(sock->name, sock_target->name)==0)
2089 /* otherwise settle for the first available socket of the right type */
2090 for (sock=node->outputs.first; sock; sock=sock->next) {
2092 if (!socket_is_available(ntree, sock, allow_multiple))
2095 /* check for same types */
2096 if (sock->type == sock_target->type) {
2104 /* this is a bit complicated, but designed to prioritise finding
2105 * sockets of higher types, such as image, first */
2106 static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, int replace)
2109 int socktype, maxtype=0;
2112 for (sock=node->inputs.first; sock; sock=sock->next) {
2113 maxtype = MAX2(sock->type, maxtype);
2116 /* find sockets of higher 'types' first (i.e. image) */
2117 for (socktype=maxtype; socktype >= 0; socktype--) {
2118 for (sock=node->inputs.first; sock; sock=sock->next) {
2120 if (!socket_is_available(ntree, sock, replace)) {
2125 if (sock->type == socktype) {
2126 /* increment to make sure we don't keep finding
2127 * the same socket on every attempt running this function */
2138 void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
2140 ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list");
2146 for(node= snode->edittree->nodes.first; node; node= node->next) {
2147 if(node->flag & NODE_SELECT) {
2148 nli = MEM_mallocN(sizeof(bNodeListItem), "temporary node list item");
2150 BLI_addtail(nodelist, nli);
2154 /* sort nodes left to right */
2155 BLI_sortlist(nodelist, sort_nodes_locx);
2157 for (nli=nodelist->first; nli; nli=nli->next) {
2158 bNode *node_fr, *node_to;
2159 bNodeSocket *sock_fr, *sock_to;
2161 if (nli->next == NULL) break;
2163 node_fr = nli->node;
2164 node_to = nli->next->node;
2166 /* check over input sockets first */
2167 for (i=0; i<BLI_countlist(&node_to->inputs); i++) {
2169 /* find the best guess input socket */
2170 sock_to = best_socket_input(snode->edittree, node_to, i, replace);
2171 if (!sock_to) continue;
2173 /* check for an appropriate output socket to connect from */
2174 sock_fr = best_socket_output(snode->edittree, node_fr, sock_to, allow_multiple);
2175 if (!sock_fr) continue;
2177 /* then we can connect */
2179 nodeRemSocketLinks(snode->edittree, sock_to);
2181 link = nodeAddLink(snode->edittree, node_fr, sock_fr, node_to, sock_to);
2182 /* validate the new link */
2183 ntreeUpdateTree(snode->edittree);
2184 if (!(link->flag & NODE_LINK_VALID)) {
2185 nodeRemLink(snode->edittree, link);
2189 snode_tag_changed(snode, node_to);
2196 ntreeUpdateTree(snode->edittree);
2199 BLI_freelistN(nodelist);
2200 MEM_freeN(nodelist);
2203 /* can be called from menus too, but they should do own undopush and redraws */
2204 bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene, bNodeTemplate *ntemp, float locx, float locy)
2206 bNode *node= NULL, *gnode;
2208 node_deselectall(snode);
2210 node = nodeAddNode(snode->edittree, ntemp);
2215 node->locy= locy + 60.0f; // arbitrary.. so its visible, (0,0) is top of node
2216 node->flag |= SELECT;
2218 gnode= node_tree_get_editgroup(snode->nodetree);
2220 node->locx -= gnode->locx;
2221 node->locy -= gnode->locy;
2224 ntreeUpdateTree(snode->edittree);
2225 ED_node_set_active(bmain, snode->edittree, node);
2227 if(snode->nodetree->type==NTREE_COMPOSIT) {
2228 if(ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE))
2229 node->id = &scene->id;
2231 ntreeCompositForceHidden(snode->edittree, scene);
2235 id_us_plus(node->id);
2237 snode_tag_changed(snode, node);
2240 if(snode->nodetree->type==NTREE_TEXTURE) {
2241 ntreeTexCheckCyclics(snode->edittree);
2247 /* ****************** Duplicate *********************** */
2249 static int node_duplicate_exec(bContext *C, wmOperator *op)
2251 SpaceNode *snode= CTX_wm_space_node(C);
2252 bNodeTree *ntree= snode->edittree;
2253 bNode *node, *newnode, *lastnode;
2254 bNodeLink *link, *newlink, *lastlink;
2255 int keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
2257 ED_preview_kill_jobs(C);
2259 lastnode = ntree->nodes.last;
2260 for(node= ntree->nodes.first; node; node= node->next) {
2261 if(node->flag & SELECT) {
2262 newnode = nodeCopyNode(ntree, node);
2265 /* simple id user adjustment, node internal functions dont touch this
2266 * but operators and readfile.c do. */
2267 id_us_plus(newnode->id);
2268 /* to ensure redraws or rerenders happen */
2269 ED_node_changed_update(snode->id, newnode);
2273 /* make sure we don't copy new nodes again! */
2278 /* copy links between selected nodes
2279 * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
2281 lastlink = ntree->links.last;
2282 for (link=ntree->links.first; link; link=link->next) {
2283 /* This creates new links between copied nodes.
2284 * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)!
2286 if (link->tonode && (link->tonode->flag & NODE_SELECT)
2287 && (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) {
2288 newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink");
2289 newlink->flag = link->flag;
2290 newlink->tonode = link->tonode->new_node;
2291 newlink->tosock = link->tosock->new_sock;
2292 if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
2293 newlink->fromnode = link->fromnode->new_node;
2294 newlink->fromsock = link->fromsock->new_sock;
2297 /* input node not copied, this keeps the original input linked */
2298 newlink->fromnode = link->fromnode;
2299 newlink->fromsock = link->fromsock;
2302 BLI_addtail(&ntree->links, newlink);
2305 /* make sure we don't copy new links again! */
2310 /* deselect old nodes, select the copies instead */
2311 for(node= ntree->nodes.first; node; node= node->next) {
2312 if(node->flag & SELECT) {
2313 /* has been set during copy above */
2314 newnode = node->new_node;
2316 node->flag &= ~(NODE_SELECT|NODE_ACTIVE);
2317 newnode->flag |= NODE_SELECT;
2320 /* make sure we don't copy new nodes again! */
2325 ntreeUpdateTree(snode->edittree);
2327 snode_notify(C, snode);
2328 snode_dag_update(C, snode);
2330 return OPERATOR_FINISHED;
2333 void NODE_OT_duplicate(wmOperatorType *ot)
2336 ot->name= "Duplicate Nodes";
2337 ot->description = "Duplicate the nodes";
2338 ot->idname= "NODE_OT_duplicate";
2341 ot->exec= node_duplicate_exec;
2342 ot->poll= ED_operator_node_active;
2345 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2347 RNA_def_boolean(ot->srna, "keep_inputs", 0, "Keep Inputs", "Keep the input links to duplicated nodes");
2350 /* *************************** add link op ******************** */
2352 static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link)
2357 if(tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
2359 for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
2360 if(link!=tlink && tlink->tosock==link->tosock)
2364 /* try to move the existing link to the next available socket */
2365 if (tlink->tonode) {
2366 /* is there a free input socket with the target type? */
2367 for(sock= tlink->tonode->inputs.first; sock; sock= sock->next) {
2368 if(sock->type==tlink->tosock->type)
2369 if(nodeCountSocketLinks(snode->edittree, sock) < sock->limit)
2373 tlink->tosock= sock;
2374 sock->flag &= ~SOCK_HIDDEN;
2377 nodeRemLink(snode->edittree, tlink);
2381 nodeRemLink(snode->edittree, tlink);
2386 /* loop that adds a nodelink, called by function below */
2387 /* in_out = starting socket */
2388 static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event)
2390 SpaceNode *snode= CTX_wm_space_node(C);
2391 ARegion *ar= CTX_wm_region(C);
2392 bNodeLinkDrag *nldrag= op->customdata;
2393 bNode *tnode, *node;
2394 bNodeSocket *tsock= NULL, *sock;
2398 in_out= nldrag->in_out;
2403 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
2404 &snode->mx, &snode->my);
2406 switch (event->type) {
2409 if(in_out==SOCK_OUT) {
2410 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
2411 if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
2412 if( link->tosock!= tsock && (!tnode || (tnode!=node && link->tonode!=tnode)) ) {
2413 link->tonode= tnode;
2414 link->tosock= tsock;
2415 if (link->prev==NULL && link->next==NULL) {
2416 BLI_addtail(&snode->edittree->links, link);
2419 snode->edittree->update |= NTREE_UPDATE_LINKS;
2420 ntreeUpdateTree(snode->edittree);
2425 if (link->tonode || link->tosock) {
2426 BLI_remlink(&snode->edittree->links, link);
2427 link->prev = link->next = NULL;
2431 snode->edittree->update |= NTREE_UPDATE_LINKS;
2432 ntreeUpdateTree(snode->edittree);
2437 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
2438 if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
2439 if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) {
2440 if( link->fromsock!= tsock && (!tnode || (tnode!=node && link->fromnode!=tnode)) ) {
2441 link->fromnode= tnode;
2442 link->fromsock= tsock;
2443 if (link->prev==NULL && link->next==NULL) {
2444 BLI_addtail(&snode->edittree->links, link);
2447 snode->edittree->update |= NTREE_UPDATE_LINKS;
2448 ntreeUpdateTree(snode->edittree);
2454 if (link->tonode || link->tosock) {
2455 BLI_remlink(&snode->edittree->links, link);
2456 link->prev = link->next = NULL;
2457 link->fromnode= NULL;
2458 link->fromsock= NULL;
2459 snode->edittree->update |= NTREE_UPDATE_LINKS;
2460 ntreeUpdateTree(snode->edittree);
2464 /* hilight target sockets only */
2465 node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT);
2466 ED_region_tag_redraw(ar);
2472 if(link->tosock && link->fromsock) {
2473 /* send changed events for original tonode and new */
2474 snode_tag_changed(snode, link->tonode);
2476 /* we might need to remove a link */
2477 if(in_out==SOCK_OUT)
2478 node_remove_extra_links(snode, link->tosock, link);
2480 /* when linking to group outputs, update the socket type */
2481 /* XXX this should all be part of a generic update system */
2482 if (!link->tonode) {
2483 link->tosock->type = link->fromsock->type;
2486 else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) {
2487 /* automatically add new group socket */
2488 if (link->tonode && link->tosock) {
2489 link->fromsock = node_group_expose_socket(snode->edittree, link->tosock, SOCK_IN);
2490 link->fromnode = NULL;
2491 if (link->prev==NULL && link->next==NULL) {
2492 BLI_addtail(&snode->edittree->links, link);
2494 snode->edittree->update |= NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_LINKS;
2496 else if (link->fromnode && link->fromsock) {
2497 link->tosock = node_group_expose_socket(snode->edittree, link->fromsock, SOCK_OUT);
2498 link->tonode = NULL;
2499 if (link->prev==NULL && link->next==NULL) {
2500 BLI_addtail(&snode->edittree->links, link);
2502 snode->edittree->update |= NTREE_UPDATE_GROUP_OUT | NTREE_UPDATE_LINKS;
2506 nodeRemLink(snode->edittree, link);
2508 ntreeUpdateTree(snode->edittree);
2509 snode_notify(C, snode);
2510 snode_dag_update(C, snode);
2512 BLI_remlink(&snode->linkdrag, nldrag);
2515 return OPERATOR_FINISHED;
2518 return OPERATOR_RUNNING_MODAL;
2521 /* return 1 when socket clicked */
2522 static int node_link_init(SpaceNode *snode, bNodeLinkDrag *nldrag)
2526 /* output indicated? */
2527 if(find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_OUT)) {
2528 if(nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit)
2531 /* find if we break a link */
2532 for(link= snode->edittree->links.first; link; link= link->next) {
2533 if(link->fromsock==nldrag->sock)
2537 nldrag->node= link->tonode;
2538 nldrag->sock= link->tosock;
2539 nodeRemLink(snode->edittree, link);
2545 else if(find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_IN)) {
2546 if(nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit)
2549 /* find if we break a link */
2550 for(link= snode->edittree->links.first; link; link= link->next) {
2551 if(link->tosock==nldrag->sock)
2555 /* send changed event to original tonode */
2557 snode_tag_changed(snode, link->tonode);
2559 nldrag->node= link->fromnode;
2560 nldrag->sock= link->fromsock;
2561 nodeRemLink(snode->edittree, link);
2570 static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event)
2572 SpaceNode *snode= CTX_wm_space_node(C);
2573 ARegion *ar= CTX_wm_region(C);
2574 bNodeLinkDrag *nldrag= MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
2577 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
2578 &snode->mx, &snode->my);
2580 ED_preview_kill_jobs(C);
2582 nldrag->in_out= node_link_init(snode, nldrag);
2584 if(nldrag->in_out) {
2585 op->customdata= nldrag;
2587 /* we make a temporal link */
2588 if(nldrag->in_out==SOCK_OUT) {
2589 nldrag->link= MEM_callocN(sizeof(bNodeLink), "link");
2590 nldrag->link->fromnode= nldrag->node;
2591 nldrag->link->fromsock= nldrag->sock;
2592 nldrag->link->tonode= NULL;
2593 nldrag->link->tosock= NULL;
2596 nldrag->link= MEM_callocN(sizeof(bNodeLink), "link");
2597 nldrag->link->fromnode= NULL;
2598 nldrag->link->fromsock= NULL;
2599 nldrag->link->tonode= nldrag->node;
2600 nldrag->link->tosock= nldrag->sock;
2602 BLI_addtail(&snode->linkdrag, nldrag);
2604 /* add modal handler */
2605 WM_event_add_modal_handler(C, op);
2607 return OPERATOR_RUNNING_MODAL;
2611 return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
2615 static int node_link_cancel(bContext *C, wmOperator *op)
2617 SpaceNode *snode= CTX_wm_space_node(C);
2618 bNodeLinkDrag *nldrag= op->customdata;
2620 nodeRemLink(snode->edittree, nldrag->link);
2621 BLI_remlink(&snode->linkdrag, nldrag);
2624 return OPERATOR_CANCELLED;
2627 void NODE_OT_link(wmOperatorType *ot)
2630 ot->name= "Link Nodes";
2631 ot->idname= "NODE_OT_link";
2634 ot->invoke= node_link_invoke;
2635 ot->modal= node_link_modal;
2636 // ot->exec= node_link_exec;
2637 ot->poll= ED_operator_node_active;
2638 ot->cancel= node_link_cancel;
2641 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2644 /* ********************** Make Link operator ***************** */
2646 /* makes a link between selected output and input sockets */
2647 static int node_make_link_exec(bContext *C, wmOperator *op)
2649 SpaceNode *snode= CTX_wm_space_node(C);
2650 int replace = RNA_boolean_get(op->ptr, "replace");
2652 ED_preview_kill_jobs(C);
2654 snode_autoconnect(snode, 1, replace);
2656 ntreeUpdateTree(snode->edittree);
2657 snode_notify(C, snode);
2658 snode_dag_update(C, snode);
2660 return OPERATOR_FINISHED;
2663 void NODE_OT_link_make(wmOperatorType *ot)
2666 ot->name= "Make Links";
2667 ot->description= "Makes a link between selected output in input sockets";
2668 ot->idname= "NODE_OT_link_make";
2671 ot->exec= node_make_link_exec;
2672 ot->poll= ED_operator_node_active; // XXX we need a special poll which checks that there are selected input/output sockets
2675 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2677 RNA_def_boolean(ot->srna, "replace", 0, "Replace", "Replace socket connections with the new links");
2680 /* ********************** Cut Link operator ***************** */
2682 #define LINK_RESOL 12
2683 static int cut_links_intersect(bNodeLink *link, float mcoords[][2], int tot)
2685 float coord_array[LINK_RESOL+1][2];
2688 if(node_link_bezier_points(NULL, NULL, link, coord_array, LINK_RESOL)) {
2690 for(i=0; i<tot-1; i++)
2691 for(b=0; b<LINK_RESOL; b++)
2692 if(isect_line_line_v2(mcoords[i], mcoords[i+1], coord_array[b], coord_array[b+1]) > 0)
2698 static int cut_links_exec(bContext *C, wmOperator *op)
2700 SpaceNode *snode= CTX_wm_space_node(C);
2701 ARegion *ar= CTX_wm_region(C);
2702 float mcoords[256][2];
2705 RNA_BEGIN(op->ptr, itemptr, "path") {
2708 RNA_float_get_array(&itemptr, "loc", loc);
2709 UI_view2d_region_to_view(&ar->v2d, (short)loc[0], (short)loc[1],
2710 &mcoords[i][0], &mcoords[i][1]);
2717 bNodeLink *link, *next;
2719 ED_preview_kill_jobs(C);
2721 for(link= snode->edittree->links.first; link; link= next) {
2724 if(cut_links_intersect(link, mcoords, i)) {
2725 snode_tag_changed(snode, link->tonode);
2726 nodeRemLink(snode->edittree, link);
2730 ntreeUpdateTree(snode->edittree);
2731 snode_notify(C, snode);
2732 snode_dag_update(C, snode);
2734 return OPERATOR_FINISHED;
2737 return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
2740 void NODE_OT_links_cut(wmOperatorType *ot)
2744 ot->name= "Cut links";
2745 ot->idname= "NODE_OT_links_cut";
2747 ot->invoke= WM_gesture_lines_invoke;
2748 ot->modal= WM_gesture_lines_modal;
2749 ot->exec= cut_links_exec;
2750 ot->cancel= WM_gesture_lines_cancel;
2752 ot->poll= ED_operator_node_active;
2755 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2757 prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
2758 RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
2760 RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
2763 /* ********************* automatic node insert on dragging ******************* */
2765 /* assumes sockets in list */
2766 static bNodeSocket *socket_best_match(ListBase *sockets, int type)
2770 /* first, match type */
2771 for(sock= sockets->first; sock; sock= sock->next)
2772 if(!(sock->flag & SOCK_HIDDEN))
2773 if(type == sock->type)
2776 /* then just use first unhidden socket */
2777 for(sock= sockets->first; sock; sock= sock->next)
2778 if(!(sock->flag & SOCK_HIDDEN))
2781 /* OK, let's unhide proper one */
2782 for(sock= sockets->first; sock; sock= sock->next) {
2783 if(type == sock->type) {
2784 sock->flag &= ~SOCK_HIDDEN;
2789 /* just the first */
2790 sock= sockets->first;
2791 sock->flag &= ~SOCK_HIDDEN;
2793 return sockets->first;
2796 /* prevent duplicate testing code below */
2797 static SpaceNode *ed_node_link_conditions(ScrArea *sa, bNode **select)
2799 SpaceNode *snode= sa?sa->spacedata.first:NULL;
2803 /* no unlucky accidents */
2804 if(sa==NULL || sa->spacetype!=SPACE_NODE) return NULL;
2808 for(node= snode->edittree->nodes.first; node; node= node->next) {
2809 if(node->flag & SELECT) {
2816 /* only one selected */
2817 if(node || *select==NULL) return NULL;
2820 if((*select)->inputs.first==NULL || (*select)->outputs.first==NULL) return NULL;
2822 /* test node for links */
2823 for(link= snode->edittree->links.first; link; link=link->next) {
2824 if(link->tonode == *select || link->fromnode == *select)
2831 /* assumes link with NODE_LINKFLAG_HILITE set */
2832 void ED_node_link_insert(ScrArea *sa)
2834 bNode *node, *select;
2835 SpaceNode *snode= ed_node_link_conditions(sa, &select);
2837 bNodeSocket *sockto;
2839 if(snode==NULL) return;
2842 for(link= snode->edittree->links.first; link; link=link->next)
2843 if(link->flag & NODE_LINKFLAG_HILITE)
2848 sockto= link->tosock;
2850 link->tonode= select;
2851 link->tosock= socket_best_match(&select->inputs, link->fromsock->type);
2852 link->flag &= ~NODE_LINKFLAG_HILITE;
2854 nodeAddLink(snode->edittree, select, socket_best_match(&select->outputs, sockto->type), node, sockto);
2855 ntreeUpdateTree(snode->edittree); /* needed for pointers */
2856 snode_tag_changed(snode, select);
2857 ED_node_changed_update(snode->id, select);
2862 /* test == 0, clear all intersect flags */
2863 void ED_node_link_intersect_test(ScrArea *sa, int test)
2866 SpaceNode *snode= ed_node_link_conditions(sa, &select);
2867 bNodeLink *link, *selink=NULL;
2868 float mcoords[6][2];
2870 if(snode==NULL) return;
2873 for(link= snode->edittree->links.first; link; link=link->next)
2874 link->flag &= ~NODE_LINKFLAG_HILITE;
2878 /* okay, there's 1 node, without links, now intersect */
2879 mcoords[0][0]= select->totr.xmin;
2880 mcoords[0][1]= select->totr.ymin;
2881 mcoords[1][0]= select->totr.xmax;
2882 mcoords[1][1]= select->totr.ymin;
2883 mcoords[2][0]= select->totr.xmax;
2884 mcoords[2][1]= select->totr.ymax;
2885 mcoords[3][0]= select->totr.xmin;
2886 mcoords[3][1]= select->totr.ymax;
2887 mcoords[4][0]= select->totr.xmin;
2888 mcoords[4][1]= select->totr.ymin;
2889 mcoords[5][0]= select->totr.xmax;
2890 mcoords[5][1]= select->totr.ymax;
2892 /* we only tag a single link for intersect now */
2893 /* idea; use header dist when more? */
2894 for(link= snode->edittree->links.first; link; link=link->next) {
2896 if(cut_links_intersect(link, mcoords, 5)) { /* intersect code wants edges */
2903 if(link==NULL && selink)
2904 selink->flag |= NODE_LINKFLAG_HILITE;
2908 /* ******************************** */
2909 // XXX some code needing updating to operators...
2912 /* goes over all scenes, reads render layers */
2913 static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
2915 Main *bmain= CTX_data_main(C);
2916 SpaceNode *snode= CTX_wm_space_node(C);
2917 Scene *curscene= CTX_data_scene(C), *scene;
2920 ED_preview_kill_jobs(C);
2922 /* first tag scenes unread */
2923 for(scene= bmain->scene.first; scene; scene= scene->id.next)
2924 scene->id.flag |= LIB_DOIT;
2926 for(node= snode->edittree->nodes.first; node; node= node->next) {
2927 if(node->type==CMP_NODE_R_LAYERS) {
2929 if(id->flag & LIB_DOIT) {
2930 RE_ReadRenderResult(curscene, (Scene *)id);
2931 ntreeCompositTagRender((Scene *)id);
2932 id->flag &= ~LIB_DOIT;
2937 snode_notify(C, snode);
2938 snode_dag_update(C, snode);
2940 return OPERATOR_FINISHED;
2943 void NODE_OT_read_renderlayers(wmOperatorType *ot)
2946 ot->name= "Read Render Layers";
2947 ot->idname= "NODE_OT_read_renderlayers";
2949 ot->exec= node_read_renderlayers_exec;
2951 ot->poll= composite_node_active;
2957 static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op))
2959 Main *bmain= CTX_data_main(C);
2960 SpaceNode *snode= CTX_wm_space_node(C);
2961 Scene *curscene= CTX_data_scene(C);
2962 Render *re= RE_NewRender(curscene->id.name);
2966 RE_MergeFullSample(re, bmain, curscene, snode->nodetree);
2967 snode_notify(C, snode);
2968 snode_dag_update(C, snode);
2971 return OPERATOR_FINISHED;
2975 void NODE_OT_read_fullsamplelayers(wmOperatorType *ot)
2978 ot->name= "Read Full Sample Layers";
2979 ot->idname= "NODE_OT_read_fullsamplelayers";
2981 ot->exec= node_read_fullsamplelayers_exec;
2983 ot->poll= composite_node_active;
2989 int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op))
2991 Scene *sce= CTX_data_scene(C);
2994 for(node= sce->nodetree->nodes.first; node; node= node->next) {
2995 if(node->id==(ID *)sce && node->need_exec) {
3000 SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
3005 WM_operator_properties_create(&op_ptr, "RENDER_OT_render");
3006 RNA_string_set(&op_ptr, "layer", srl->name);
3007 RNA_string_set(&op_ptr, "scene", sce->id.name+2);
3009 /* to keep keypositions */
3010 sce->r.scemode |= R_NO_FRAME_UPDATE;
3012 WM_operator_name_call(C, "RENDER_OT_render", WM_OP_INVOKE_DEFAULT, &op_ptr);
3014 WM_operator_properties_free(&op_ptr);
3016 return OPERATOR_FINISHED;
3020 return OPERATOR_CANCELLED;
3023 void NODE_OT_render_changed(wmOperatorType *ot)
3026 ot->name= "Render Changed Layer";
3027 ot->idname= "NODE_OT_render_changed";
3029 ot->exec= node_render_changed_exec;
3031 ot->poll= composite_node_active;
3038 /* ****************** Make Group operator ******************* */
3040 static int node_group_make_exec(bContext *C, wmOperator *op)
3042 SpaceNode *snode = CTX_wm_space_node(C);
3045 if(snode->edittree!=snode->nodetree) {
3046 BKE_report(op->reports, RPT_WARNING, "Can not add a new Group in a Group");
3047 return OPERATOR_CANCELLED;
3050 /* for time being... is too complex to handle */
3051 if(snode->treetype==NTREE_COMPOSIT) {
3052 for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
3053 if(gnode->flag & SELECT)
3054 if(gnode->type==CMP_NODE_R_LAYERS)
3059 BKE_report(op->reports, RPT_WARNING, "Can not add RenderLayer in a Group");
3060 return OPERATOR_CANCELLED;
3064 ED_preview_kill_jobs(C);
3066 gnode= node_group_make_from_selected(snode->nodetree);
3068 BKE_report(op->reports, RPT_WARNING, "Can not make Group");
3069 return OPERATOR_CANCELLED;
3072 nodeSetActive(snode->nodetree, gnode);
3073 ntreeUpdateTree(snode->nodetree);
3076 snode_notify(C, snode);
3077 snode_dag_update(C, snode);
3079 return OPERATOR_FINISHED;
3082 void NODE_OT_group_make(wmOperatorType *ot)
3086 ot->description = "Make group from selected nodes";
3087 ot->idname = "NODE_OT_group_make";
3090 ot->exec = node_group_make_exec;
3091 ot->poll = ED_operator_node_active;
3094 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3097 /* ****************** Hide operator *********************** */