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 
20 /** \file
21  * \ingroup spnode
22  */
23 
24 #include "MEM_guardedalloc.h"
25 
26 #include "DNA_light_types.h"
27 #include "DNA_material_types.h"
28 #include "DNA_node_types.h"
29 #include "DNA_text_types.h"
30 #include "DNA_world_types.h"
31 
32 #include "BLI_blenlib.h"
33 #include "BLI_math.h"
34 
35 #include "BKE_context.h"
36 #include "BKE_global.h"
37 #include "BKE_image.h"
38 #include "BKE_lib_id.h"
39 #include "BKE_main.h"
40 #include "BKE_material.h"
41 #include "BKE_node.h"
42 #include "BKE_report.h"
43 #include "BKE_scene.h"
44 
45 #include "DEG_depsgraph.h"
46 #include "DEG_depsgraph_build.h"
47 #include "DEG_depsgraph_query.h"
48 
49 #include "RE_engine.h"
50 #include "RE_pipeline.h"
51 
52 #include "ED_node.h" /* own include */
53 #include "ED_render.h"
54 #include "ED_screen.h"
55 #include "ED_select_utils.h"
56 
57 #include "RNA_access.h"
58 #include "RNA_define.h"
59 #include "RNA_enum_types.h"
60 
61 #include "WM_api.h"
62 #include "WM_types.h"
63 
64 #include "UI_view2d.h"
65 
66 #include "GPU_material.h"
67 
68 #include "IMB_imbuf_types.h"
69 
70 #include "NOD_composite.h"
71 #include "NOD_shader.h"
72 #include "NOD_simulation.h"
73 #include "NOD_texture.h"
74 #include "node_intern.h" /* own include */
75 
76 #define USE_ESC_COMPO
77 
78 /* ***************** composite job manager ********************** */
79 
80 enum {
81   COM_RECALC_COMPOSITE = 1,
82   COM_RECALC_VIEWER = 2,
83 };
84 
85 typedef struct CompoJob {
86   /* Input parameters. */
87   Main *bmain;
88   Scene *scene;
89   ViewLayer *view_layer;
90   bNodeTree *ntree;
91   int recalc_flags;
92   /* Evaluated state/ */
93   Depsgraph *compositor_depsgraph;
94   bNodeTree *localtree;
95   /* Jon system integration. */
96   const short *stop;
97   short *do_update;
98   float *progress;
99 } CompoJob;
100 
compo_tag_output_nodes(bNodeTree * nodetree,int recalc_flags)101 static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
102 {
103   bNode *node;
104 
105   for (node = nodetree->nodes.first; node; node = node->next) {
106     if (node->type == CMP_NODE_COMPOSITE) {
107       if (recalc_flags & COM_RECALC_COMPOSITE) {
108         node->flag |= NODE_DO_OUTPUT_RECALC;
109       }
110     }
111     else if (node->type == CMP_NODE_VIEWER || node->type == CMP_NODE_SPLITVIEWER) {
112       if (recalc_flags & COM_RECALC_VIEWER) {
113         node->flag |= NODE_DO_OUTPUT_RECALC;
114       }
115     }
116     else if (node->type == NODE_GROUP) {
117       if (node->id) {
118         compo_tag_output_nodes((bNodeTree *)node->id, recalc_flags);
119       }
120     }
121   }
122 }
123 
compo_get_recalc_flags(const bContext * C)124 static int compo_get_recalc_flags(const bContext *C)
125 {
126   wmWindowManager *wm = CTX_wm_manager(C);
127   wmWindow *win;
128   int recalc_flags = 0;
129 
130   for (win = wm->windows.first; win; win = win->next) {
131     const bScreen *screen = WM_window_get_active_screen(win);
132     ScrArea *area;
133 
134     for (area = screen->areabase.first; area; area = area->next) {
135       if (area->spacetype == SPACE_IMAGE) {
136         SpaceImage *sima = area->spacedata.first;
137         if (sima->image) {
138           if (sima->image->type == IMA_TYPE_R_RESULT) {
139             recalc_flags |= COM_RECALC_COMPOSITE;
140           }
141           else if (sima->image->type == IMA_TYPE_COMPOSITE) {
142             recalc_flags |= COM_RECALC_VIEWER;
143           }
144         }
145       }
146       else if (area->spacetype == SPACE_NODE) {
147         SpaceNode *snode = area->spacedata.first;
148         if (snode->flag & SNODE_BACKDRAW) {
149           recalc_flags |= COM_RECALC_VIEWER;
150         }
151       }
152     }
153   }
154 
155   return recalc_flags;
156 }
157 
158 /* called by compo, only to check job 'stop' value */
compo_breakjob(void * cjv)159 static int compo_breakjob(void *cjv)
160 {
161   CompoJob *cj = cjv;
162 
163   /* without G.is_break 'ESC' wont quit - which annoys users */
164   return (*(cj->stop)
165 #ifdef USE_ESC_COMPO
166           || G.is_break
167 #endif
168   );
169 }
170 
171 /* called by compo, wmJob sends notifier */
compo_statsdrawjob(void * cjv,const char * UNUSED (str))172 static void compo_statsdrawjob(void *cjv, const char *UNUSED(str))
173 {
174   CompoJob *cj = cjv;
175 
176   *(cj->do_update) = true;
177 }
178 
179 /* called by compo, wmJob sends notifier */
compo_redrawjob(void * cjv)180 static void compo_redrawjob(void *cjv)
181 {
182   CompoJob *cj = cjv;
183 
184   *(cj->do_update) = true;
185 }
186 
compo_freejob(void * cjv)187 static void compo_freejob(void *cjv)
188 {
189   CompoJob *cj = cjv;
190 
191   if (cj->localtree) {
192     ntreeLocalMerge(cj->bmain, cj->localtree, cj->ntree);
193   }
194   if (cj->compositor_depsgraph != NULL) {
195     DEG_graph_free(cj->compositor_depsgraph);
196   }
197   MEM_freeN(cj);
198 }
199 
200 /* only now we copy the nodetree, so adding many jobs while
201  * sliding buttons doesn't frustrate */
compo_initjob(void * cjv)202 static void compo_initjob(void *cjv)
203 {
204   CompoJob *cj = cjv;
205   Main *bmain = cj->bmain;
206   Scene *scene = cj->scene;
207   ViewLayer *view_layer = cj->view_layer;
208 
209   cj->compositor_depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
210   DEG_graph_build_for_compositor_preview(cj->compositor_depsgraph, cj->ntree);
211 
212   /* NOTE: Don't update animation to preserve unkeyed changes, this means can not use
213    * evaluate_on_framechange. */
214   DEG_evaluate_on_refresh(cj->compositor_depsgraph);
215 
216   bNodeTree *ntree_eval = (bNodeTree *)DEG_get_evaluated_id(cj->compositor_depsgraph,
217                                                             &cj->ntree->id);
218 
219   cj->localtree = ntreeLocalize(ntree_eval);
220 
221   if (cj->recalc_flags) {
222     compo_tag_output_nodes(cj->localtree, cj->recalc_flags);
223   }
224 }
225 
226 /* called before redraw notifiers, it moves finished previews over */
compo_updatejob(void * UNUSED (cjv))227 static void compo_updatejob(void *UNUSED(cjv))
228 {
229   WM_main_add_notifier(NC_SCENE | ND_COMPO_RESULT, NULL);
230 }
231 
compo_progressjob(void * cjv,float progress)232 static void compo_progressjob(void *cjv, float progress)
233 {
234   CompoJob *cj = cjv;
235 
236   *(cj->progress) = progress;
237 }
238 
239 /* only this runs inside thread */
compo_startjob(void * cjv,short * stop,short * do_update,float * progress)240 static void compo_startjob(void *cjv,
241                            /* Cannot be const, this function implements wm_jobs_start_callback.
242                             * NOLINTNEXTLINE: readability-non-const-parameter. */
243                            short *stop,
244                            short *do_update,
245                            float *progress)
246 {
247   CompoJob *cj = cjv;
248   bNodeTree *ntree = cj->localtree;
249   Scene *scene = cj->scene;
250   SceneRenderView *srv;
251 
252   if (scene->use_nodes == false) {
253     return;
254   }
255 
256   cj->stop = stop;
257   cj->do_update = do_update;
258   cj->progress = progress;
259 
260   ntree->test_break = compo_breakjob;
261   ntree->tbh = cj;
262   ntree->stats_draw = compo_statsdrawjob;
263   ntree->sdh = cj;
264   ntree->progress = compo_progressjob;
265   ntree->prh = cj;
266   ntree->update_draw = compo_redrawjob;
267   ntree->udh = cj;
268 
269   // XXX BIF_store_spare();
270   /* 1 is do_previews */
271 
272   if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
273     ntreeCompositExecTree(cj->scene,
274                           ntree,
275                           &cj->scene->r,
276                           false,
277                           true,
278                           &scene->view_settings,
279                           &scene->display_settings,
280                           "");
281   }
282   else {
283     for (srv = scene->r.views.first; srv; srv = srv->next) {
284       if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) {
285         continue;
286       }
287       ntreeCompositExecTree(cj->scene,
288                             ntree,
289                             &cj->scene->r,
290                             false,
291                             true,
292                             &scene->view_settings,
293                             &scene->display_settings,
294                             srv->name);
295     }
296   }
297 
298   ntree->test_break = NULL;
299   ntree->stats_draw = NULL;
300   ntree->progress = NULL;
301 }
302 
303 /**
304  * \param scene_owner: is the owner of the job,
305  * we don't use it for anything else currently so could also be a void pointer,
306  * but for now keep it an 'Scene' for consistency.
307  *
308  * \note only call from spaces `refresh` callbacks, not direct! - use with care.
309  */
ED_node_composite_job(const bContext * C,struct bNodeTree * nodetree,Scene * scene_owner)310 void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner)
311 {
312   wmJob *wm_job;
313   CompoJob *cj;
314   Main *bmain = CTX_data_main(C);
315   Scene *scene = CTX_data_scene(C);
316   ViewLayer *view_layer = CTX_data_view_layer(C);
317 
318   /* to fix bug: T32272. */
319   if (G.is_rendering) {
320     return;
321   }
322 
323 #ifdef USE_ESC_COMPO
324   G.is_break = false;
325 #endif
326 
327   BKE_image_backup_render(
328       scene, BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"), false);
329 
330   wm_job = WM_jobs_get(CTX_wm_manager(C),
331                        CTX_wm_window(C),
332                        scene_owner,
333                        "Compositing",
334                        WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS,
335                        WM_JOB_TYPE_COMPOSITE);
336   cj = MEM_callocN(sizeof(CompoJob), "compo job");
337 
338   /* customdata for preview thread */
339   cj->bmain = bmain;
340   cj->scene = scene;
341   cj->view_layer = view_layer;
342   cj->ntree = nodetree;
343   cj->recalc_flags = compo_get_recalc_flags(C);
344 
345   /* setup job */
346   WM_jobs_customdata_set(wm_job, cj, compo_freejob);
347   WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_COMPO_RESULT, NC_SCENE | ND_COMPO_RESULT);
348   WM_jobs_callbacks(wm_job, compo_startjob, compo_initjob, compo_updatejob, NULL);
349 
350   WM_jobs_start(CTX_wm_manager(C), wm_job);
351 }
352 
353 /* ***************************************** */
354 
355 /* operator poll callback */
composite_node_active(bContext * C)356 bool composite_node_active(bContext *C)
357 {
358   if (ED_operator_node_active(C)) {
359     SpaceNode *snode = CTX_wm_space_node(C);
360     if (ED_node_is_compositor(snode)) {
361       return true;
362     }
363   }
364   return false;
365 }
366 
367 /* operator poll callback */
composite_node_editable(bContext * C)368 bool composite_node_editable(bContext *C)
369 {
370   if (ED_operator_node_editable(C)) {
371     SpaceNode *snode = CTX_wm_space_node(C);
372     if (ED_node_is_compositor(snode)) {
373       return true;
374     }
375   }
376   return false;
377 }
378 
snode_dag_update(bContext * C,SpaceNode * snode)379 void snode_dag_update(bContext *C, SpaceNode *snode)
380 {
381   Main *bmain = CTX_data_main(C);
382 
383   /* for groups, update all ID's using this */
384   if (snode->edittree != snode->nodetree) {
385     FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
386       if (ntreeHasTree(tntree, snode->edittree)) {
387         DEG_id_tag_update(id, 0);
388       }
389     }
390     FOREACH_NODETREE_END;
391   }
392 
393   DEG_id_tag_update(snode->id, 0);
394 }
395 
snode_notify(bContext * C,SpaceNode * snode)396 void snode_notify(bContext *C, SpaceNode *snode)
397 {
398   ID *id = snode->id;
399 
400   WM_event_add_notifier(C, NC_NODE | NA_EDITED, NULL);
401 
402   if (ED_node_is_shader(snode)) {
403     if (GS(id->name) == ID_MA) {
404       WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
405     }
406     else if (GS(id->name) == ID_LA) {
407       WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id);
408     }
409     else if (GS(id->name) == ID_WO) {
410       WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
411     }
412   }
413   else if (ED_node_is_compositor(snode)) {
414     WM_event_add_notifier(C, NC_SCENE | ND_NODES, id);
415   }
416   else if (ED_node_is_texture(snode)) {
417     WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id);
418   }
419 }
420 
ED_node_set_tree_type(SpaceNode * snode,bNodeTreeType * typeinfo)421 void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
422 {
423   if (typeinfo) {
424     BLI_strncpy(snode->tree_idname, typeinfo->idname, sizeof(snode->tree_idname));
425   }
426   else {
427     snode->tree_idname[0] = '\0';
428   }
429 }
430 
ED_node_is_compositor(struct SpaceNode * snode)431 bool ED_node_is_compositor(struct SpaceNode *snode)
432 {
433   return STREQ(snode->tree_idname, ntreeType_Composite->idname);
434 }
435 
ED_node_is_shader(struct SpaceNode * snode)436 bool ED_node_is_shader(struct SpaceNode *snode)
437 {
438   return STREQ(snode->tree_idname, ntreeType_Shader->idname);
439 }
440 
ED_node_is_texture(struct SpaceNode * snode)441 bool ED_node_is_texture(struct SpaceNode *snode)
442 {
443   return STREQ(snode->tree_idname, ntreeType_Texture->idname);
444 }
445 
ED_node_is_simulation(struct SpaceNode * snode)446 bool ED_node_is_simulation(struct SpaceNode *snode)
447 {
448   return STREQ(snode->tree_idname, ntreeType_Simulation->idname);
449 }
450 
451 /* assumes nothing being done in ntree yet, sets the default in/out node */
452 /* called from shading buttons or header */
ED_node_shader_default(const bContext * C,ID * id)453 void ED_node_shader_default(const bContext *C, ID *id)
454 {
455   Main *bmain = CTX_data_main(C);
456 
457   if (GS(id->name) == ID_MA) {
458     /* Materials */
459     Object *ob = CTX_data_active_object(C);
460     Material *ma = (Material *)id;
461     Material *ma_default;
462 
463     if (ob && ob->type == OB_VOLUME) {
464       ma_default = BKE_material_default_volume();
465     }
466     else {
467       ma_default = BKE_material_default_surface();
468     }
469 
470     ma->nodetree = ntreeCopyTree(bmain, ma_default->nodetree);
471     ntreeUpdateTree(bmain, ma->nodetree);
472   }
473   else if (ELEM(GS(id->name), ID_WO, ID_LA)) {
474     /* Emission */
475     bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
476     bNode *shader, *output;
477 
478     if (GS(id->name) == ID_WO) {
479       World *world = (World *)id;
480       world->nodetree = ntree;
481 
482       shader = nodeAddStaticNode(NULL, ntree, SH_NODE_BACKGROUND);
483       output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_WORLD);
484       nodeAddLink(ntree,
485                   shader,
486                   nodeFindSocket(shader, SOCK_OUT, "Background"),
487                   output,
488                   nodeFindSocket(output, SOCK_IN, "Surface"));
489 
490       bNodeSocket *color_sock = nodeFindSocket(shader, SOCK_IN, "Color");
491       copy_v3_v3(((bNodeSocketValueRGBA *)color_sock->default_value)->value, &world->horr);
492     }
493     else {
494       Light *light = (Light *)id;
495       light->nodetree = ntree;
496 
497       shader = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION);
498       output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_LIGHT);
499       nodeAddLink(ntree,
500                   shader,
501                   nodeFindSocket(shader, SOCK_OUT, "Emission"),
502                   output,
503                   nodeFindSocket(output, SOCK_IN, "Surface"));
504     }
505 
506     shader->locx = 10.0f;
507     shader->locy = 300.0f;
508     output->locx = 300.0f;
509     output->locy = 300.0f;
510     nodeSetActive(ntree, output);
511     ntreeUpdateTree(bmain, ntree);
512   }
513   else {
514     printf("ED_node_shader_default called on wrong ID type.\n");
515     return;
516   }
517 }
518 
519 /* assumes nothing being done in ntree yet, sets the default in/out node */
520 /* called from shading buttons or header */
ED_node_composit_default(const bContext * C,struct Scene * sce)521 void ED_node_composit_default(const bContext *C, struct Scene *sce)
522 {
523   bNode *in, *out;
524   bNodeSocket *fromsock, *tosock;
525 
526   /* but lets check it anyway */
527   if (sce->nodetree) {
528     if (G.debug & G_DEBUG) {
529       printf("error in composite initialize\n");
530     }
531     return;
532   }
533 
534   sce->nodetree = ntreeAddTree(NULL, "Compositing Nodetree", ntreeType_Composite->idname);
535 
536   sce->nodetree->chunksize = 256;
537   sce->nodetree->edit_quality = NTREE_QUALITY_HIGH;
538   sce->nodetree->render_quality = NTREE_QUALITY_HIGH;
539 
540   out = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_COMPOSITE);
541   out->locx = 300.0f;
542   out->locy = 400.0f;
543 
544   in = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_R_LAYERS);
545   in->locx = 10.0f;
546   in->locy = 400.0f;
547   nodeSetActive(sce->nodetree, in);
548 
549   /* links from color to color */
550   fromsock = in->outputs.first;
551   tosock = out->inputs.first;
552   nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
553 
554   ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
555 }
556 
557 /* assumes nothing being done in ntree yet, sets the default in/out node */
558 /* called from shading buttons or header */
ED_node_texture_default(const bContext * C,Tex * tex)559 void ED_node_texture_default(const bContext *C, Tex *tex)
560 {
561   bNode *in, *out;
562   bNodeSocket *fromsock, *tosock;
563 
564   /* but lets check it anyway */
565   if (tex->nodetree) {
566     if (G.debug & G_DEBUG) {
567       printf("error in texture initialize\n");
568     }
569     return;
570   }
571 
572   tex->nodetree = ntreeAddTree(NULL, "Texture Nodetree", ntreeType_Texture->idname);
573 
574   out = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_OUTPUT);
575   out->locx = 300.0f;
576   out->locy = 300.0f;
577 
578   in = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_CHECKER);
579   in->locx = 10.0f;
580   in->locy = 300.0f;
581   nodeSetActive(tex->nodetree, in);
582 
583   fromsock = in->outputs.first;
584   tosock = out->inputs.first;
585   nodeAddLink(tex->nodetree, in, fromsock, out, tosock);
586 
587   ntreeUpdateTree(CTX_data_main(C), tex->nodetree);
588 }
589 
590 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
snode_set_context(const bContext * C)591 void snode_set_context(const bContext *C)
592 {
593   SpaceNode *snode = CTX_wm_space_node(C);
594   bNodeTreeType *treetype = ntreeTypeFind(snode->tree_idname);
595   bNodeTree *ntree = snode->nodetree;
596   ID *id = snode->id, *from = snode->from;
597 
598   /* check the tree type */
599   if (!treetype || (treetype->poll && !treetype->poll(C, treetype))) {
600     /* invalid tree type, skip
601      * NB: not resetting the node path here, invalid bNodeTreeType
602      * may still be registered at a later point.
603      */
604     return;
605   }
606 
607   if (snode->nodetree && !STREQ(snode->nodetree->idname, snode->tree_idname)) {
608     /* current tree does not match selected type, clear tree path */
609     ntree = NULL;
610     id = NULL;
611     from = NULL;
612   }
613 
614   if (!(snode->flag & SNODE_PIN) || ntree == NULL) {
615     if (treetype->get_from_context) {
616       /* reset and update from context */
617       ntree = NULL;
618       id = NULL;
619       from = NULL;
620 
621       treetype->get_from_context(C, treetype, &ntree, &id, &from);
622     }
623   }
624 
625   if (snode->nodetree != ntree || snode->id != id || snode->from != from ||
626       (snode->treepath.last == NULL && ntree)) {
627     ED_node_tree_start(snode, ntree, id, from);
628   }
629 }
630 
snode_update(SpaceNode * snode,bNode * node)631 void snode_update(SpaceNode *snode, bNode *node)
632 {
633   bNodeTreePath *path;
634 
635   /* XXX this only updates nodes in the current node space tree path.
636    * The function supposedly should update any potential group node linking to changed tree,
637    * this really requires a working depsgraph ...
638    */
639 
640   /* update all edited group nodes */
641   path = snode->treepath.last;
642   if (path) {
643     bNodeTree *ngroup = path->nodetree;
644     for (path = path->prev; path; path = path->prev) {
645       nodeUpdateID(path->nodetree, (ID *)ngroup);
646       ngroup = path->nodetree;
647     }
648   }
649 
650   if (node) {
651     nodeUpdate(snode->edittree, node);
652   }
653 }
654 
ED_node_set_active(Main * bmain,bNodeTree * ntree,bNode * node,bool * r_active_texture_changed)655 void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
656 {
657   const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0;
658   if (r_active_texture_changed) {
659     *r_active_texture_changed = false;
660   }
661 
662   nodeSetActive(ntree, node);
663 
664   if (node->type != NODE_GROUP) {
665     const bool was_output = (node->flag & NODE_DO_OUTPUT) != 0;
666     bool do_update = false;
667 
668     /* generic node group output: set node as active output */
669     if (node->type == NODE_GROUP_OUTPUT) {
670       bNode *tnode;
671       for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
672         if (tnode->type == NODE_GROUP_OUTPUT) {
673           tnode->flag &= ~NODE_DO_OUTPUT;
674         }
675       }
676 
677       node->flag |= NODE_DO_OUTPUT;
678       if (!was_output) {
679         do_update = 1;
680       }
681     }
682 
683     /* tree specific activate calls */
684     if (ntree->type == NTREE_SHADER) {
685       /* when we select a material, active texture is cleared, for buttons */
686       if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO)) {
687         nodeClearActiveID(ntree, ID_TE);
688       }
689 
690       if (ELEM(node->type,
691                SH_NODE_OUTPUT_MATERIAL,
692                SH_NODE_OUTPUT_WORLD,
693                SH_NODE_OUTPUT_LIGHT,
694                SH_NODE_OUTPUT_LINESTYLE)) {
695         bNode *tnode;
696 
697         for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
698           if (tnode->type == node->type) {
699             tnode->flag &= ~NODE_DO_OUTPUT;
700           }
701         }
702 
703         node->flag |= NODE_DO_OUTPUT;
704         if (was_output == 0) {
705           ED_node_tag_update_nodetree(bmain, ntree, node);
706         }
707       }
708       else if (do_update) {
709         ED_node_tag_update_nodetree(bmain, ntree, node);
710       }
711 
712       /* if active texture changed, free glsl materials */
713       if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
714         Material *ma;
715         World *wo;
716 
717         for (ma = bmain->materials.first; ma; ma = ma->id.next) {
718           if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree)) {
719             GPU_material_free(&ma->gpumaterial);
720           }
721         }
722 
723         for (wo = bmain->worlds.first; wo; wo = wo->id.next) {
724           if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree)) {
725             GPU_material_free(&wo->gpumaterial);
726           }
727         }
728 
729         if (r_active_texture_changed) {
730           *r_active_texture_changed = true;
731         }
732         ED_node_tag_update_nodetree(bmain, ntree, node);
733         WM_main_add_notifier(NC_IMAGE, NULL);
734       }
735 
736       WM_main_add_notifier(NC_MATERIAL | ND_NODES, node->id);
737     }
738     else if (ntree->type == NTREE_COMPOSIT) {
739       /* make active viewer, currently only 1 supported... */
740       if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
741         bNode *tnode;
742 
743         for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
744           if (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
745             tnode->flag &= ~NODE_DO_OUTPUT;
746           }
747         }
748 
749         node->flag |= NODE_DO_OUTPUT;
750         if (was_output == 0) {
751           ED_node_tag_update_nodetree(bmain, ntree, node);
752         }
753 
754         /* addnode() doesn't link this yet... */
755         node->id = (ID *)BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
756       }
757       else if (node->type == CMP_NODE_COMPOSITE) {
758         if (was_output == 0) {
759           bNode *tnode;
760 
761           for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
762             if (tnode->type == CMP_NODE_COMPOSITE) {
763               tnode->flag &= ~NODE_DO_OUTPUT;
764             }
765           }
766 
767           node->flag |= NODE_DO_OUTPUT;
768           ED_node_tag_update_nodetree(bmain, ntree, node);
769         }
770       }
771       else if (do_update) {
772         ED_node_tag_update_nodetree(bmain, ntree, node);
773       }
774     }
775     else if (ntree->type == NTREE_TEXTURE) {
776       /* XXX */
777 #if 0
778       if (node->id) {
779         BIF_preview_changed(-1);
780         allqueue(REDRAWBUTSSHADING, 1);
781         allqueue(REDRAWIPO, 0);
782       }
783 #endif
784     }
785   }
786 }
787 
ED_node_post_apply_transform(bContext * UNUSED (C),bNodeTree * UNUSED (ntree))788 void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
789 {
790   /* XXX This does not work due to layout functions relying on node->block,
791    * which only exists during actual drawing. Can we rely on valid totr rects?
792    */
793   /* make sure nodes have correct bounding boxes after transform */
794   /* node_update_nodetree(C, ntree, 0.0f, 0.0f); */
795 }
796 
797 /* ***************** generic operator functions for nodes ***************** */
798 
799 #if 0 /* UNUSED */
800 
801 static bool edit_node_poll(bContext *C)
802 {
803   return ED_operator_node_active(C);
804 }
805 
806 static void edit_node_properties(wmOperatorType *ot)
807 {
808   /* XXX could node be a context pointer? */
809   RNA_def_string(ot->srna, "node", NULL, MAX_NAME, "Node", "");
810   RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET);
811   RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Side", "");
812 }
813 
814 static int edit_node_invoke_properties(bContext *C, wmOperator *op)
815 {
816   if (!RNA_struct_property_is_set(op->ptr, "node")) {
817     bNode *node = CTX_data_pointer_get_type(C, "node", &RNA_Node).data;
818     if (!node) {
819       return 0;
820     }
821     else {
822       RNA_string_set(op->ptr, "node", node->name);
823     }
824   }
825 
826   if (!RNA_struct_property_is_set(op->ptr, "in_out")) {
827     RNA_enum_set(op->ptr, "in_out", SOCK_IN);
828   }
829 
830   if (!RNA_struct_property_is_set(op->ptr, "socket")) {
831     RNA_int_set(op->ptr, "socket", 0);
832   }
833 
834   return 1;
835 }
836 
837 static void edit_node_properties_get(
838     wmOperator *op, bNodeTree *ntree, bNode **r_node, bNodeSocket **r_sock, int *r_in_out)
839 {
840   bNode *node;
841   bNodeSocket *sock = NULL;
842   char nodename[MAX_NAME];
843   int sockindex;
844   int in_out;
845 
846   RNA_string_get(op->ptr, "node", nodename);
847   node = nodeFindNodebyName(ntree, nodename);
848 
849   in_out = RNA_enum_get(op->ptr, "in_out");
850 
851   sockindex = RNA_int_get(op->ptr, "socket");
852   switch (in_out) {
853     case SOCK_IN:
854       sock = BLI_findlink(&node->inputs, sockindex);
855       break;
856     case SOCK_OUT:
857       sock = BLI_findlink(&node->outputs, sockindex);
858       break;
859   }
860 
861   if (r_node) {
862     *r_node = node;
863   }
864   if (r_sock) {
865     *r_sock = sock;
866   }
867   if (r_in_out) {
868     *r_in_out = in_out;
869   }
870 }
871 #endif
872 
873 /* ************************** Node generic ************** */
874 
875 /* is rct in visible part of node? */
visible_node(SpaceNode * snode,const rctf * rct)876 static bNode *visible_node(SpaceNode *snode, const rctf *rct)
877 {
878   bNode *node;
879 
880   for (node = snode->edittree->nodes.last; node; node = node->prev) {
881     if (BLI_rctf_isect(&node->totr, rct, NULL)) {
882       break;
883     }
884   }
885   return node;
886 }
887 
888 /* ********************** size widget operator ******************** */
889 
890 typedef struct NodeSizeWidget {
891   float mxstart, mystart;
892   float oldlocx, oldlocy;
893   float oldoffsetx, oldoffsety;
894   float oldwidth, oldheight;
895   int directions;
896 } NodeSizeWidget;
897 
node_resize_init(bContext * C,wmOperator * op,const wmEvent * UNUSED (event),bNode * node,int dir)898 static void node_resize_init(
899     bContext *C, wmOperator *op, const wmEvent *UNUSED(event), bNode *node, int dir)
900 {
901   SpaceNode *snode = CTX_wm_space_node(C);
902 
903   NodeSizeWidget *nsw = MEM_callocN(sizeof(NodeSizeWidget), "size widget op data");
904 
905   op->customdata = nsw;
906   nsw->mxstart = snode->cursor[0] * UI_DPI_FAC;
907   nsw->mystart = snode->cursor[1] * UI_DPI_FAC;
908 
909   /* store old */
910   nsw->oldlocx = node->locx;
911   nsw->oldlocy = node->locy;
912   nsw->oldoffsetx = node->offsetx;
913   nsw->oldoffsety = node->offsety;
914   nsw->oldwidth = node->width;
915   nsw->oldheight = node->height;
916   nsw->directions = dir;
917 
918   WM_cursor_modal_set(CTX_wm_window(C), node_get_resize_cursor(dir));
919   /* add modal handler */
920   WM_event_add_modal_handler(C, op);
921 }
922 
node_resize_exit(bContext * C,wmOperator * op,bool cancel)923 static void node_resize_exit(bContext *C, wmOperator *op, bool cancel)
924 {
925   WM_cursor_modal_restore(CTX_wm_window(C));
926 
927   /* Restore old data on cancel. */
928   if (cancel) {
929     SpaceNode *snode = CTX_wm_space_node(C);
930     bNode *node = nodeGetActive(snode->edittree);
931     NodeSizeWidget *nsw = op->customdata;
932 
933     node->locx = nsw->oldlocx;
934     node->locy = nsw->oldlocy;
935     node->offsetx = nsw->oldoffsetx;
936     node->offsety = nsw->oldoffsety;
937     node->width = nsw->oldwidth;
938     node->height = nsw->oldheight;
939   }
940 
941   MEM_freeN(op->customdata);
942   op->customdata = NULL;
943 }
944 
node_resize_modal(bContext * C,wmOperator * op,const wmEvent * event)945 static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
946 {
947   SpaceNode *snode = CTX_wm_space_node(C);
948   ARegion *region = CTX_wm_region(C);
949   bNode *node = nodeGetActive(snode->edittree);
950   NodeSizeWidget *nsw = op->customdata;
951   float mx, my, dx, dy;
952 
953   switch (event->type) {
954     case MOUSEMOVE:
955 
956       UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &mx, &my);
957       dx = (mx - nsw->mxstart) / UI_DPI_FAC;
958       dy = (my - nsw->mystart) / UI_DPI_FAC;
959 
960       if (node) {
961         float *pwidth;
962         float oldwidth, widthmin, widthmax;
963 
964         pwidth = &node->width;
965         oldwidth = nsw->oldwidth;
966         widthmin = node->typeinfo->minwidth;
967         widthmax = node->typeinfo->maxwidth;
968 
969         {
970           if (nsw->directions & NODE_RESIZE_RIGHT) {
971             *pwidth = oldwidth + dx;
972             CLAMP(*pwidth, widthmin, widthmax);
973           }
974           if (nsw->directions & NODE_RESIZE_LEFT) {
975             float locmax = nsw->oldlocx + oldwidth;
976 
977             node->locx = nsw->oldlocx + dx;
978             CLAMP(node->locx, locmax - widthmax, locmax - widthmin);
979             *pwidth = locmax - node->locx;
980           }
981         }
982 
983         /* height works the other way round ... */
984         {
985           float heightmin = UI_DPI_FAC * node->typeinfo->minheight;
986           float heightmax = UI_DPI_FAC * node->typeinfo->maxheight;
987           if (nsw->directions & NODE_RESIZE_TOP) {
988             float locmin = nsw->oldlocy - nsw->oldheight;
989 
990             node->locy = nsw->oldlocy + dy;
991             CLAMP(node->locy, locmin + heightmin, locmin + heightmax);
992             node->height = node->locy - locmin;
993           }
994           if (nsw->directions & NODE_RESIZE_BOTTOM) {
995             node->height = nsw->oldheight - dy;
996             CLAMP(node->height, heightmin, heightmax);
997           }
998         }
999 
1000         /* XXX make callback? */
1001         if (node->type == NODE_FRAME) {
1002           /* keep the offset symmetric around center point */
1003           if (nsw->directions & NODE_RESIZE_LEFT) {
1004             node->locx = nsw->oldlocx + 0.5f * dx;
1005             node->offsetx = nsw->oldoffsetx + 0.5f * dx;
1006           }
1007           if (nsw->directions & NODE_RESIZE_RIGHT) {
1008             node->locx = nsw->oldlocx + 0.5f * dx;
1009             node->offsetx = nsw->oldoffsetx - 0.5f * dx;
1010           }
1011           if (nsw->directions & NODE_RESIZE_TOP) {
1012             node->locy = nsw->oldlocy + 0.5f * dy;
1013             node->offsety = nsw->oldoffsety + 0.5f * dy;
1014           }
1015           if (nsw->directions & NODE_RESIZE_BOTTOM) {
1016             node->locy = nsw->oldlocy + 0.5f * dy;
1017             node->offsety = nsw->oldoffsety - 0.5f * dy;
1018           }
1019         }
1020       }
1021 
1022       ED_region_tag_redraw(region);
1023 
1024       break;
1025 
1026     case LEFTMOUSE:
1027     case MIDDLEMOUSE:
1028     case RIGHTMOUSE:
1029       if (event->val == KM_RELEASE) {
1030         node_resize_exit(C, op, false);
1031         ED_node_post_apply_transform(C, snode->edittree);
1032 
1033         return OPERATOR_FINISHED;
1034       }
1035       else if (event->val == KM_PRESS) {
1036         node_resize_exit(C, op, true);
1037         ED_region_tag_redraw(region);
1038 
1039         return OPERATOR_CANCELLED;
1040       }
1041       break;
1042   }
1043 
1044   return OPERATOR_RUNNING_MODAL;
1045 }
1046 
node_resize_invoke(bContext * C,wmOperator * op,const wmEvent * event)1047 static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1048 {
1049   SpaceNode *snode = CTX_wm_space_node(C);
1050   ARegion *region = CTX_wm_region(C);
1051   bNode *node = nodeGetActive(snode->edittree);
1052   int dir;
1053 
1054   if (node) {
1055     float cursor[2];
1056 
1057     /* convert mouse coordinates to v2d space */
1058     UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
1059     dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]);
1060     if (dir != 0) {
1061       node_resize_init(C, op, event, node, dir);
1062       return OPERATOR_RUNNING_MODAL;
1063     }
1064   }
1065   return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
1066 }
1067 
node_resize_cancel(bContext * C,wmOperator * op)1068 static void node_resize_cancel(bContext *C, wmOperator *op)
1069 {
1070   node_resize_exit(C, op, true);
1071 }
1072 
NODE_OT_resize(wmOperatorType * ot)1073 void NODE_OT_resize(wmOperatorType *ot)
1074 {
1075   /* identifiers */
1076   ot->name = "Resize Node";
1077   ot->idname = "NODE_OT_resize";
1078   ot->description = "Resize a node";
1079 
1080   /* api callbacks */
1081   ot->invoke = node_resize_invoke;
1082   ot->modal = node_resize_modal;
1083   ot->poll = ED_operator_node_active;
1084   ot->cancel = node_resize_cancel;
1085 
1086   /* flags */
1087   ot->flag = OPTYPE_BLOCKING;
1088 }
1089 
1090 /* ********************** hidden sockets ******************** */
1091 
node_has_hidden_sockets(bNode * node)1092 bool node_has_hidden_sockets(bNode *node)
1093 {
1094   bNodeSocket *sock;
1095 
1096   for (sock = node->inputs.first; sock; sock = sock->next) {
1097     if (sock->flag & SOCK_HIDDEN) {
1098       return true;
1099     }
1100   }
1101   for (sock = node->outputs.first; sock; sock = sock->next) {
1102     if (sock->flag & SOCK_HIDDEN) {
1103       return true;
1104     }
1105   }
1106   return false;
1107 }
1108 
node_set_hidden_sockets(SpaceNode * snode,bNode * node,int set)1109 void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
1110 {
1111   bNodeSocket *sock;
1112 
1113   if (set == 0) {
1114     for (sock = node->inputs.first; sock; sock = sock->next) {
1115       sock->flag &= ~SOCK_HIDDEN;
1116     }
1117     for (sock = node->outputs.first; sock; sock = sock->next) {
1118       sock->flag &= ~SOCK_HIDDEN;
1119     }
1120   }
1121   else {
1122     /* hide unused sockets */
1123     for (sock = node->inputs.first; sock; sock = sock->next) {
1124       if (sock->link == NULL) {
1125         sock->flag |= SOCK_HIDDEN;
1126       }
1127     }
1128     for (sock = node->outputs.first; sock; sock = sock->next) {
1129       if (nodeCountSocketLinks(snode->edittree, sock) == 0) {
1130         sock->flag |= SOCK_HIDDEN;
1131       }
1132     }
1133   }
1134 }
1135 
1136 /* checks snode->mouse position, and returns found node/socket */
1137 /* type is SOCK_IN and/or SOCK_OUT */
node_find_indicated_socket(SpaceNode * snode,bNode ** nodep,bNodeSocket ** sockp,float cursor[2],int in_out)1138 int node_find_indicated_socket(
1139     SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, float cursor[2], int in_out)
1140 {
1141   bNode *node;
1142   bNodeSocket *sock;
1143   rctf rect;
1144 
1145   *nodep = NULL;
1146   *sockp = NULL;
1147 
1148   /* check if we click in a socket */
1149   for (node = snode->edittree->nodes.first; node; node = node->next) {
1150 
1151     BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4);
1152 
1153     if (!(node->flag & NODE_HIDDEN)) {
1154       /* extra padding inside and out - allow dragging on the text areas too */
1155       if (in_out == SOCK_IN) {
1156         rect.xmax += NODE_SOCKSIZE;
1157         rect.xmin -= NODE_SOCKSIZE * 4;
1158       }
1159       else if (in_out == SOCK_OUT) {
1160         rect.xmax += NODE_SOCKSIZE * 4;
1161         rect.xmin -= NODE_SOCKSIZE;
1162       }
1163     }
1164 
1165     if (in_out & SOCK_IN) {
1166       for (sock = node->inputs.first; sock; sock = sock->next) {
1167         if (!nodeSocketIsHidden(sock)) {
1168           if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
1169             if (node == visible_node(snode, &rect)) {
1170               *nodep = node;
1171               *sockp = sock;
1172               return 1;
1173             }
1174           }
1175         }
1176       }
1177     }
1178     if (in_out & SOCK_OUT) {
1179       for (sock = node->outputs.first; sock; sock = sock->next) {
1180         if (!nodeSocketIsHidden(sock)) {
1181           if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
1182             if (node == visible_node(snode, &rect)) {
1183               *nodep = node;
1184               *sockp = sock;
1185               return 1;
1186             }
1187           }
1188         }
1189       }
1190     }
1191   }
1192 
1193   return 0;
1194 }
1195 
1196 /* ****************** Duplicate *********************** */
1197 
node_duplicate_reparent_recursive(bNode * node)1198 static void node_duplicate_reparent_recursive(bNode *node)
1199 {
1200   bNode *parent;
1201 
1202   node->flag |= NODE_TEST;
1203 
1204   /* find first selected parent */
1205   for (parent = node->parent; parent; parent = parent->parent) {
1206     if (parent->flag & SELECT) {
1207       if (!(parent->flag & NODE_TEST)) {
1208         node_duplicate_reparent_recursive(parent);
1209       }
1210       break;
1211     }
1212   }
1213   /* reparent node copy to parent copy */
1214   if (parent) {
1215     nodeDetachNode(node->new_node);
1216     nodeAttachNode(node->new_node, parent->new_node);
1217   }
1218 }
1219 
node_duplicate_exec(bContext * C,wmOperator * op)1220 static int node_duplicate_exec(bContext *C, wmOperator *op)
1221 {
1222   Main *bmain = CTX_data_main(C);
1223   SpaceNode *snode = CTX_wm_space_node(C);
1224   bNodeTree *ntree = snode->edittree;
1225   bNode *node, *newnode, *lastnode;
1226   bNodeLink *link, *newlink, *lastlink;
1227   const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
1228   bool do_tag_update = false;
1229 
1230   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1231 
1232   lastnode = ntree->nodes.last;
1233   for (node = ntree->nodes.first; node; node = node->next) {
1234     if (node->flag & SELECT) {
1235       newnode = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
1236 
1237       /* to ensure redraws or rerenders happen */
1238       ED_node_tag_update_id(snode->id);
1239     }
1240 
1241     /* make sure we don't copy new nodes again! */
1242     if (node == lastnode) {
1243       break;
1244     }
1245   }
1246 
1247   /* copy links between selected nodes
1248    * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
1249    */
1250   lastlink = ntree->links.last;
1251   for (link = ntree->links.first; link; link = link->next) {
1252     /* This creates new links between copied nodes.
1253      * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)!
1254      */
1255     if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
1256         (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) {
1257       newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink");
1258       newlink->flag = link->flag;
1259       newlink->tonode = link->tonode->new_node;
1260       newlink->tosock = link->tosock->new_sock;
1261       if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
1262         newlink->fromnode = link->fromnode->new_node;
1263         newlink->fromsock = link->fromsock->new_sock;
1264       }
1265       else {
1266         /* input node not copied, this keeps the original input linked */
1267         newlink->fromnode = link->fromnode;
1268         newlink->fromsock = link->fromsock;
1269       }
1270 
1271       BLI_addtail(&ntree->links, newlink);
1272     }
1273 
1274     /* make sure we don't copy new links again! */
1275     if (link == lastlink) {
1276       break;
1277     }
1278   }
1279 
1280   /* clear flags for recursive depth-first iteration */
1281   for (node = ntree->nodes.first; node; node = node->next) {
1282     node->flag &= ~NODE_TEST;
1283   }
1284   /* reparent copied nodes */
1285   for (node = ntree->nodes.first; node; node = node->next) {
1286     if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) {
1287       node_duplicate_reparent_recursive(node);
1288     }
1289 
1290     /* only has to check old nodes */
1291     if (node == lastnode) {
1292       break;
1293     }
1294   }
1295 
1296   /* deselect old nodes, select the copies instead */
1297   for (node = ntree->nodes.first; node; node = node->next) {
1298     if (node->flag & SELECT) {
1299       /* has been set during copy above */
1300       newnode = node->new_node;
1301 
1302       nodeSetSelected(node, false);
1303       node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
1304       nodeSetSelected(newnode, true);
1305 
1306       do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode));
1307     }
1308 
1309     /* make sure we don't copy new nodes again! */
1310     if (node == lastnode) {
1311       break;
1312     }
1313   }
1314 
1315   ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1316 
1317   snode_notify(C, snode);
1318   if (do_tag_update) {
1319     snode_dag_update(C, snode);
1320   }
1321 
1322   return OPERATOR_FINISHED;
1323 }
1324 
NODE_OT_duplicate(wmOperatorType * ot)1325 void NODE_OT_duplicate(wmOperatorType *ot)
1326 {
1327   /* identifiers */
1328   ot->name = "Duplicate Nodes";
1329   ot->description = "Duplicate selected nodes";
1330   ot->idname = "NODE_OT_duplicate";
1331 
1332   /* api callbacks */
1333   ot->exec = node_duplicate_exec;
1334   ot->poll = ED_operator_node_editable;
1335 
1336   /* flags */
1337   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1338 
1339   RNA_def_boolean(
1340       ot->srna, "keep_inputs", 0, "Keep Inputs", "Keep the input links to duplicated nodes");
1341 }
1342 
ED_node_select_check(ListBase * lb)1343 bool ED_node_select_check(ListBase *lb)
1344 {
1345   LISTBASE_FOREACH (bNode *, node, lb) {
1346     if (node->flag & NODE_SELECT) {
1347       return true;
1348     }
1349   }
1350 
1351   return false;
1352 }
1353 
ED_node_select_all(ListBase * lb,int action)1354 void ED_node_select_all(ListBase *lb, int action)
1355 {
1356   if (action == SEL_TOGGLE) {
1357     if (ED_node_select_check(lb)) {
1358       action = SEL_DESELECT;
1359     }
1360     else {
1361       action = SEL_SELECT;
1362     }
1363   }
1364 
1365   LISTBASE_FOREACH (bNode *, node, lb) {
1366     switch (action) {
1367       case SEL_SELECT:
1368         nodeSetSelected(node, true);
1369         break;
1370       case SEL_DESELECT:
1371         nodeSetSelected(node, false);
1372         break;
1373       case SEL_INVERT:
1374         nodeSetSelected(node, !(node->flag & SELECT));
1375         break;
1376     }
1377   }
1378 }
1379 
1380 /* ******************************** */
1381 /* XXX some code needing updating to operators. */
1382 
1383 /* goes over all scenes, reads render layers */
node_read_viewlayers_exec(bContext * C,wmOperator * UNUSED (op))1384 static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
1385 {
1386   Main *bmain = CTX_data_main(C);
1387   SpaceNode *snode = CTX_wm_space_node(C);
1388   Scene *curscene = CTX_data_scene(C), *scene;
1389   bNode *node;
1390 
1391   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1392 
1393   /* first tag scenes unread */
1394   for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
1395     scene->id.tag |= LIB_TAG_DOIT;
1396   }
1397 
1398   for (node = snode->edittree->nodes.first; node; node = node->next) {
1399     if (node->type == CMP_NODE_R_LAYERS) {
1400       ID *id = node->id;
1401       if (id->tag & LIB_TAG_DOIT) {
1402         RE_ReadRenderResult(curscene, (Scene *)id);
1403         ntreeCompositTagRender((Scene *)id);
1404         id->tag &= ~LIB_TAG_DOIT;
1405       }
1406     }
1407   }
1408 
1409   snode_notify(C, snode);
1410   snode_dag_update(C, snode);
1411 
1412   return OPERATOR_FINISHED;
1413 }
1414 
NODE_OT_read_viewlayers(wmOperatorType * ot)1415 void NODE_OT_read_viewlayers(wmOperatorType *ot)
1416 {
1417 
1418   ot->name = "Read View Layers";
1419   ot->idname = "NODE_OT_read_viewlayers";
1420   ot->description = "Read all render layers of all used scenes";
1421 
1422   ot->exec = node_read_viewlayers_exec;
1423 
1424   ot->poll = composite_node_active;
1425 
1426   /* flags */
1427   ot->flag = 0;
1428 }
1429 
node_render_changed_exec(bContext * C,wmOperator * UNUSED (op))1430 int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op))
1431 {
1432   Scene *sce = CTX_data_scene(C);
1433   bNode *node;
1434 
1435   /* This is actually a test whether scene is used by the compositor or not.
1436    * All the nodes are using same render result, so there is no need to do
1437    * anything smart about check how exactly scene is used. */
1438   for (node = sce->nodetree->nodes.first; node; node = node->next) {
1439     if (node->id == (ID *)sce) {
1440       break;
1441     }
1442   }
1443 
1444   if (node) {
1445     ViewLayer *view_layer = BLI_findlink(&sce->view_layers, node->custom1);
1446 
1447     if (view_layer) {
1448       PointerRNA op_ptr;
1449 
1450       WM_operator_properties_create(&op_ptr, "RENDER_OT_render");
1451       RNA_string_set(&op_ptr, "layer", view_layer->name);
1452       RNA_string_set(&op_ptr, "scene", sce->id.name + 2);
1453 
1454       /* to keep keypositions */
1455       sce->r.scemode |= R_NO_FRAME_UPDATE;
1456 
1457       WM_operator_name_call(C, "RENDER_OT_render", WM_OP_INVOKE_DEFAULT, &op_ptr);
1458 
1459       WM_operator_properties_free(&op_ptr);
1460 
1461       return OPERATOR_FINISHED;
1462     }
1463   }
1464   return OPERATOR_CANCELLED;
1465 }
1466 
NODE_OT_render_changed(wmOperatorType * ot)1467 void NODE_OT_render_changed(wmOperatorType *ot)
1468 {
1469   ot->name = "Render Changed Layer";
1470   ot->idname = "NODE_OT_render_changed";
1471   ot->description = "Render current scene, when input node's layer has been changed";
1472 
1473   ot->exec = node_render_changed_exec;
1474 
1475   ot->poll = composite_node_active;
1476 
1477   /* flags */
1478   ot->flag = 0;
1479 }
1480 
1481 /* ****************** Hide operator *********************** */
1482 
node_flag_toggle_exec(SpaceNode * snode,int toggle_flag)1483 static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag)
1484 {
1485   bNode *node;
1486   int tot_eq = 0, tot_neq = 0;
1487 
1488   /* Toggles the flag on all selected nodes.
1489    * If the flag is set on all nodes it is unset.
1490    * If the flag is not set on all nodes, it is set.
1491    */
1492   for (node = snode->edittree->nodes.first; node; node = node->next) {
1493     if (node->flag & SELECT) {
1494 
1495       if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0) {
1496         continue;
1497       }
1498       if (toggle_flag == NODE_OPTIONS &&
1499           !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex)) {
1500         continue;
1501       }
1502 
1503       if (node->flag & toggle_flag) {
1504         tot_eq++;
1505       }
1506       else {
1507         tot_neq++;
1508       }
1509     }
1510   }
1511   for (node = snode->edittree->nodes.first; node; node = node->next) {
1512     if (node->flag & SELECT) {
1513 
1514       if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0) {
1515         continue;
1516       }
1517       if (toggle_flag == NODE_OPTIONS &&
1518           !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex)) {
1519         continue;
1520       }
1521 
1522       if ((tot_eq && tot_neq) || tot_eq == 0) {
1523         node->flag |= toggle_flag;
1524       }
1525       else {
1526         node->flag &= ~toggle_flag;
1527       }
1528     }
1529   }
1530 }
1531 
node_hide_toggle_exec(bContext * C,wmOperator * UNUSED (op))1532 static int node_hide_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1533 {
1534   SpaceNode *snode = CTX_wm_space_node(C);
1535 
1536   /* sanity checking (poll callback checks this already) */
1537   if ((snode == NULL) || (snode->edittree == NULL)) {
1538     return OPERATOR_CANCELLED;
1539   }
1540 
1541   node_flag_toggle_exec(snode, NODE_HIDDEN);
1542 
1543   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1544 
1545   return OPERATOR_FINISHED;
1546 }
1547 
NODE_OT_hide_toggle(wmOperatorType * ot)1548 void NODE_OT_hide_toggle(wmOperatorType *ot)
1549 {
1550   /* identifiers */
1551   ot->name = "Hide";
1552   ot->description = "Toggle hiding of selected nodes";
1553   ot->idname = "NODE_OT_hide_toggle";
1554 
1555   /* callbacks */
1556   ot->exec = node_hide_toggle_exec;
1557   ot->poll = ED_operator_node_active;
1558 
1559   /* flags */
1560   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1561 }
1562 
node_preview_toggle_exec(bContext * C,wmOperator * UNUSED (op))1563 static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1564 {
1565   SpaceNode *snode = CTX_wm_space_node(C);
1566 
1567   /* sanity checking (poll callback checks this already) */
1568   if ((snode == NULL) || (snode->edittree == NULL)) {
1569     return OPERATOR_CANCELLED;
1570   }
1571 
1572   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1573 
1574   node_flag_toggle_exec(snode, NODE_PREVIEW);
1575 
1576   snode_notify(C, snode);
1577 
1578   return OPERATOR_FINISHED;
1579 }
1580 
NODE_OT_preview_toggle(wmOperatorType * ot)1581 void NODE_OT_preview_toggle(wmOperatorType *ot)
1582 {
1583   /* identifiers */
1584   ot->name = "Toggle Node Preview";
1585   ot->description = "Toggle preview display for selected nodes";
1586   ot->idname = "NODE_OT_preview_toggle";
1587 
1588   /* callbacks */
1589   ot->exec = node_preview_toggle_exec;
1590   ot->poll = ED_operator_node_active;
1591 
1592   /* flags */
1593   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1594 }
1595 
node_options_toggle_exec(bContext * C,wmOperator * UNUSED (op))1596 static int node_options_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1597 {
1598   SpaceNode *snode = CTX_wm_space_node(C);
1599 
1600   /* sanity checking (poll callback checks this already) */
1601   if ((snode == NULL) || (snode->edittree == NULL)) {
1602     return OPERATOR_CANCELLED;
1603   }
1604 
1605   node_flag_toggle_exec(snode, NODE_OPTIONS);
1606 
1607   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1608 
1609   return OPERATOR_FINISHED;
1610 }
1611 
NODE_OT_options_toggle(wmOperatorType * ot)1612 void NODE_OT_options_toggle(wmOperatorType *ot)
1613 {
1614   /* identifiers */
1615   ot->name = "Toggle Node Options";
1616   ot->description = "Toggle option buttons display for selected nodes";
1617   ot->idname = "NODE_OT_options_toggle";
1618 
1619   /* callbacks */
1620   ot->exec = node_options_toggle_exec;
1621   ot->poll = ED_operator_node_active;
1622 
1623   /* flags */
1624   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1625 }
1626 
node_socket_toggle_exec(bContext * C,wmOperator * UNUSED (op))1627 static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1628 {
1629   SpaceNode *snode = CTX_wm_space_node(C);
1630   bNode *node;
1631   int hidden;
1632 
1633   /* sanity checking (poll callback checks this already) */
1634   if ((snode == NULL) || (snode->edittree == NULL)) {
1635     return OPERATOR_CANCELLED;
1636   }
1637 
1638   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1639 
1640   /* Toggle for all selected nodes */
1641   hidden = 0;
1642   for (node = snode->edittree->nodes.first; node; node = node->next) {
1643     if (node->flag & SELECT) {
1644       if (node_has_hidden_sockets(node)) {
1645         hidden = 1;
1646         break;
1647       }
1648     }
1649   }
1650 
1651   for (node = snode->edittree->nodes.first; node; node = node->next) {
1652     if (node->flag & SELECT) {
1653       node_set_hidden_sockets(snode, node, !hidden);
1654     }
1655   }
1656 
1657   ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1658 
1659   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1660 
1661   return OPERATOR_FINISHED;
1662 }
1663 
NODE_OT_hide_socket_toggle(wmOperatorType * ot)1664 void NODE_OT_hide_socket_toggle(wmOperatorType *ot)
1665 {
1666   /* identifiers */
1667   ot->name = "Toggle Hidden Node Sockets";
1668   ot->description = "Toggle unused node socket display";
1669   ot->idname = "NODE_OT_hide_socket_toggle";
1670 
1671   /* callbacks */
1672   ot->exec = node_socket_toggle_exec;
1673   ot->poll = ED_operator_node_active;
1674 
1675   /* flags */
1676   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1677 }
1678 
1679 /* ****************** Mute operator *********************** */
1680 
node_mute_exec(bContext * C,wmOperator * UNUSED (op))1681 static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
1682 {
1683   Main *bmain = CTX_data_main(C);
1684   SpaceNode *snode = CTX_wm_space_node(C);
1685   bNode *node;
1686   bool do_tag_update = false;
1687 
1688   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1689 
1690   for (node = snode->edittree->nodes.first; node; node = node->next) {
1691     /* Only allow muting of nodes having a mute func! */
1692     if ((node->flag & SELECT) && node->typeinfo->update_internal_links) {
1693       node->flag ^= NODE_MUTED;
1694       snode_update(snode, node);
1695       do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
1696     }
1697   }
1698 
1699   do_tag_update |= ED_node_is_simulation(snode);
1700 
1701   snode_notify(C, snode);
1702   if (do_tag_update) {
1703     snode_dag_update(C, snode);
1704   }
1705 
1706   return OPERATOR_FINISHED;
1707 }
1708 
NODE_OT_mute_toggle(wmOperatorType * ot)1709 void NODE_OT_mute_toggle(wmOperatorType *ot)
1710 {
1711   /* identifiers */
1712   ot->name = "Toggle Node Mute";
1713   ot->description = "Toggle muting of the nodes";
1714   ot->idname = "NODE_OT_mute_toggle";
1715 
1716   /* callbacks */
1717   ot->exec = node_mute_exec;
1718   ot->poll = ED_operator_node_editable;
1719 
1720   /* flags */
1721   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1722 }
1723 
1724 /* ****************** Delete operator ******************* */
1725 
node_delete_exec(bContext * C,wmOperator * UNUSED (op))1726 static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
1727 {
1728   Main *bmain = CTX_data_main(C);
1729   SpaceNode *snode = CTX_wm_space_node(C);
1730   bNode *node, *next;
1731   bool do_tag_update = false;
1732 
1733   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1734 
1735   for (node = snode->edittree->nodes.first; node; node = next) {
1736     next = node->next;
1737     if (node->flag & SELECT) {
1738       do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
1739       nodeRemoveNode(bmain, snode->edittree, node, true);
1740     }
1741   }
1742 
1743   do_tag_update |= ED_node_is_simulation(snode);
1744 
1745   ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1746 
1747   snode_notify(C, snode);
1748   if (do_tag_update) {
1749     snode_dag_update(C, snode);
1750   }
1751 
1752   return OPERATOR_FINISHED;
1753 }
1754 
NODE_OT_delete(wmOperatorType * ot)1755 void NODE_OT_delete(wmOperatorType *ot)
1756 {
1757   /* identifiers */
1758   ot->name = "Delete";
1759   ot->description = "Delete selected nodes";
1760   ot->idname = "NODE_OT_delete";
1761 
1762   /* api callbacks */
1763   ot->exec = node_delete_exec;
1764   ot->poll = ED_operator_node_editable;
1765 
1766   /* flags */
1767   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1768 }
1769 
1770 /* ****************** Switch View ******************* */
1771 
node_switch_view_poll(bContext * C)1772 static bool node_switch_view_poll(bContext *C)
1773 {
1774   SpaceNode *snode = CTX_wm_space_node(C);
1775 
1776   if (snode && snode->edittree) {
1777     return true;
1778   }
1779 
1780   return false;
1781 }
1782 
node_switch_view_exec(bContext * C,wmOperator * UNUSED (op))1783 static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
1784 {
1785   SpaceNode *snode = CTX_wm_space_node(C);
1786   bNode *node, *next;
1787 
1788   for (node = snode->edittree->nodes.first; node; node = next) {
1789     next = node->next;
1790     if (node->flag & SELECT) {
1791       /* call the update function from the Switch View node */
1792       node->update = NODE_UPDATE_OPERATOR;
1793     }
1794   }
1795 
1796   ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1797 
1798   snode_notify(C, snode);
1799   snode_dag_update(C, snode);
1800 
1801   return OPERATOR_FINISHED;
1802 }
1803 
NODE_OT_switch_view_update(wmOperatorType * ot)1804 void NODE_OT_switch_view_update(wmOperatorType *ot)
1805 {
1806   /* identifiers */
1807   ot->name = "Update Views";
1808   ot->description = "Update views of selected node";
1809   ot->idname = "NODE_OT_switch_view_update";
1810 
1811   /* api callbacks */
1812   ot->exec = node_switch_view_exec;
1813   ot->poll = node_switch_view_poll;
1814 
1815   /* flags */
1816   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1817 }
1818 
1819 /* ****************** Delete with reconnect ******************* */
node_delete_reconnect_exec(bContext * C,wmOperator * UNUSED (op))1820 static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
1821 {
1822   Main *bmain = CTX_data_main(C);
1823   SpaceNode *snode = CTX_wm_space_node(C);
1824   bNode *node, *next;
1825 
1826   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1827 
1828   for (node = snode->edittree->nodes.first; node; node = next) {
1829     next = node->next;
1830     if (node->flag & SELECT) {
1831       nodeInternalRelink(snode->edittree, node);
1832       nodeRemoveNode(bmain, snode->edittree, node, true);
1833     }
1834   }
1835 
1836   ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1837 
1838   snode_notify(C, snode);
1839   snode_dag_update(C, snode);
1840 
1841   return OPERATOR_FINISHED;
1842 }
1843 
NODE_OT_delete_reconnect(wmOperatorType * ot)1844 void NODE_OT_delete_reconnect(wmOperatorType *ot)
1845 {
1846   /* identifiers */
1847   ot->name = "Delete with Reconnect";
1848   ot->description = "Delete nodes; will reconnect nodes as if deletion was muted";
1849   ot->idname = "NODE_OT_delete_reconnect";
1850 
1851   /* api callbacks */
1852   ot->exec = node_delete_reconnect_exec;
1853   ot->poll = ED_operator_node_editable;
1854 
1855   /* flags */
1856   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1857 }
1858 
1859 /* ****************** File Output Add Socket  ******************* */
1860 
node_output_file_add_socket_exec(bContext * C,wmOperator * op)1861 static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
1862 {
1863   Scene *scene = CTX_data_scene(C);
1864   SpaceNode *snode = CTX_wm_space_node(C);
1865   PointerRNA ptr = CTX_data_pointer_get(C, "node");
1866   bNodeTree *ntree = NULL;
1867   bNode *node = NULL;
1868   char file_path[MAX_NAME];
1869 
1870   if (ptr.data) {
1871     node = ptr.data;
1872     ntree = (bNodeTree *)ptr.owner_id;
1873   }
1874   else if (snode && snode->edittree) {
1875     ntree = snode->edittree;
1876     node = nodeGetActive(snode->edittree);
1877   }
1878 
1879   if (!node || node->type != CMP_NODE_OUTPUT_FILE) {
1880     return OPERATOR_CANCELLED;
1881   }
1882 
1883   RNA_string_get(op->ptr, "file_path", file_path);
1884   ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
1885 
1886   snode_notify(C, snode);
1887 
1888   return OPERATOR_FINISHED;
1889 }
1890 
NODE_OT_output_file_add_socket(wmOperatorType * ot)1891 void NODE_OT_output_file_add_socket(wmOperatorType *ot)
1892 {
1893   /* identifiers */
1894   ot->name = "Add File Node Socket";
1895   ot->description = "Add a new input to a file output node";
1896   ot->idname = "NODE_OT_output_file_add_socket";
1897 
1898   /* callbacks */
1899   ot->exec = node_output_file_add_socket_exec;
1900   ot->poll = composite_node_editable;
1901 
1902   /* flags */
1903   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1904 
1905   RNA_def_string(
1906       ot->srna, "file_path", "Image", MAX_NAME, "File Path", "Sub-path of the output file");
1907 }
1908 
1909 /* ****************** Multi File Output Remove Socket  ******************* */
1910 
node_output_file_remove_active_socket_exec(bContext * C,wmOperator * UNUSED (op))1911 static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *UNUSED(op))
1912 {
1913   SpaceNode *snode = CTX_wm_space_node(C);
1914   PointerRNA ptr = CTX_data_pointer_get(C, "node");
1915   bNodeTree *ntree = NULL;
1916   bNode *node = NULL;
1917 
1918   if (ptr.data) {
1919     node = ptr.data;
1920     ntree = (bNodeTree *)ptr.owner_id;
1921   }
1922   else if (snode && snode->edittree) {
1923     ntree = snode->edittree;
1924     node = nodeGetActive(snode->edittree);
1925   }
1926 
1927   if (!node || node->type != CMP_NODE_OUTPUT_FILE) {
1928     return OPERATOR_CANCELLED;
1929   }
1930 
1931   if (!ntreeCompositOutputFileRemoveActiveSocket(ntree, node)) {
1932     return OPERATOR_CANCELLED;
1933   }
1934 
1935   snode_notify(C, snode);
1936 
1937   return OPERATOR_FINISHED;
1938 }
1939 
NODE_OT_output_file_remove_active_socket(wmOperatorType * ot)1940 void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot)
1941 {
1942   /* identifiers */
1943   ot->name = "Remove File Node Socket";
1944   ot->description = "Remove active input from a file output node";
1945   ot->idname = "NODE_OT_output_file_remove_active_socket";
1946 
1947   /* callbacks */
1948   ot->exec = node_output_file_remove_active_socket_exec;
1949   ot->poll = composite_node_editable;
1950 
1951   /* flags */
1952   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1953 }
1954 
1955 /* ****************** Multi File Output Move Socket  ******************* */
1956 
node_output_file_move_active_socket_exec(bContext * C,wmOperator * op)1957 static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
1958 {
1959   SpaceNode *snode = CTX_wm_space_node(C);
1960   PointerRNA ptr = CTX_data_pointer_get(C, "node");
1961   bNode *node = NULL;
1962   NodeImageMultiFile *nimf;
1963   bNodeSocket *sock;
1964   int direction;
1965 
1966   if (ptr.data) {
1967     node = ptr.data;
1968   }
1969   else if (snode && snode->edittree) {
1970     node = nodeGetActive(snode->edittree);
1971   }
1972 
1973   if (!node || node->type != CMP_NODE_OUTPUT_FILE) {
1974     return OPERATOR_CANCELLED;
1975   }
1976 
1977   nimf = node->storage;
1978 
1979   sock = BLI_findlink(&node->inputs, nimf->active_input);
1980   if (!sock) {
1981     return OPERATOR_CANCELLED;
1982   }
1983 
1984   direction = RNA_enum_get(op->ptr, "direction");
1985 
1986   if (direction == 1) {
1987     bNodeSocket *before = sock->prev;
1988     if (!before) {
1989       return OPERATOR_CANCELLED;
1990     }
1991     BLI_remlink(&node->inputs, sock);
1992     BLI_insertlinkbefore(&node->inputs, before, sock);
1993     nimf->active_input--;
1994   }
1995   else {
1996     bNodeSocket *after = sock->next;
1997     if (!after) {
1998       return OPERATOR_CANCELLED;
1999     }
2000     BLI_remlink(&node->inputs, sock);
2001     BLI_insertlinkafter(&node->inputs, after, sock);
2002     nimf->active_input++;
2003   }
2004 
2005   snode_notify(C, snode);
2006 
2007   return OPERATOR_FINISHED;
2008 }
2009 
NODE_OT_output_file_move_active_socket(wmOperatorType * ot)2010 void NODE_OT_output_file_move_active_socket(wmOperatorType *ot)
2011 {
2012   static const EnumPropertyItem direction_items[] = {
2013       {1, "UP", 0, "Up", ""}, {2, "DOWN", 0, "Down", ""}, {0, NULL, 0, NULL, NULL}};
2014 
2015   /* identifiers */
2016   ot->name = "Move File Node Socket";
2017   ot->description = "Move the active input of a file output node up or down the list";
2018   ot->idname = "NODE_OT_output_file_move_active_socket";
2019 
2020   /* callbacks */
2021   ot->exec = node_output_file_move_active_socket_exec;
2022   ot->poll = composite_node_editable;
2023 
2024   /* flags */
2025   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2026 
2027   RNA_def_enum(ot->srna, "direction", direction_items, 2, "Direction", "");
2028 }
2029 
2030 /* ****************** Copy Node Color ******************* */
2031 
node_copy_color_exec(bContext * C,wmOperator * UNUSED (op))2032 static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
2033 {
2034   SpaceNode *snode = CTX_wm_space_node(C);
2035   bNodeTree *ntree = snode->edittree;
2036   bNode *node, *tnode;
2037 
2038   if (!ntree) {
2039     return OPERATOR_CANCELLED;
2040   }
2041   node = nodeGetActive(ntree);
2042   if (!node) {
2043     return OPERATOR_CANCELLED;
2044   }
2045 
2046   for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
2047     if (tnode->flag & NODE_SELECT && tnode != node) {
2048       if (node->flag & NODE_CUSTOM_COLOR) {
2049         tnode->flag |= NODE_CUSTOM_COLOR;
2050         copy_v3_v3(tnode->color, node->color);
2051       }
2052       else {
2053         tnode->flag &= ~NODE_CUSTOM_COLOR;
2054       }
2055     }
2056   }
2057 
2058   ED_node_sort(ntree);
2059   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2060 
2061   return OPERATOR_FINISHED;
2062 }
2063 
NODE_OT_node_copy_color(wmOperatorType * ot)2064 void NODE_OT_node_copy_color(wmOperatorType *ot)
2065 {
2066   /* identifiers */
2067   ot->name = "Copy Color";
2068   ot->description = "Copy color to all selected nodes";
2069   ot->idname = "NODE_OT_node_copy_color";
2070 
2071   /* api callbacks */
2072   ot->exec = node_copy_color_exec;
2073   ot->poll = ED_operator_node_editable;
2074 
2075   /* flags */
2076   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2077 }
2078 
2079 /* ****************** Copy to clipboard ******************* */
2080 
node_clipboard_copy_exec(bContext * C,wmOperator * UNUSED (op))2081 static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
2082 {
2083   SpaceNode *snode = CTX_wm_space_node(C);
2084   bNodeTree *ntree = snode->edittree;
2085   bNode *node;
2086   bNodeLink *link, *newlink;
2087 
2088   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2089 
2090   /* clear current clipboard */
2091   BKE_node_clipboard_clear();
2092   BKE_node_clipboard_init(ntree);
2093 
2094   for (node = ntree->nodes.first; node; node = node->next) {
2095     if (node->flag & SELECT) {
2096       /* No ID refcounting, this node is virtual,
2097        * detached from any actual Blender data currently. */
2098       bNode *new_node = BKE_node_copy_store_new_pointers(
2099           NULL, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN);
2100       BKE_node_clipboard_add_node(new_node);
2101     }
2102   }
2103 
2104   for (node = ntree->nodes.first; node; node = node->next) {
2105     if (node->flag & SELECT) {
2106       bNode *new_node = node->new_node;
2107 
2108       /* ensure valid pointers */
2109       if (new_node->parent) {
2110         /* parent pointer must be redirected to new node or detached if parent is
2111          * not copied */
2112         if (new_node->parent->flag & NODE_SELECT) {
2113           new_node->parent = new_node->parent->new_node;
2114         }
2115         else {
2116           nodeDetachNode(new_node);
2117         }
2118       }
2119     }
2120   }
2121 
2122   /* copy links between selected nodes
2123    * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
2124    */
2125   for (link = ntree->links.first; link; link = link->next) {
2126     /* This creates new links between copied nodes. */
2127     if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode &&
2128         (link->fromnode->flag & NODE_SELECT)) {
2129       newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink");
2130       newlink->flag = link->flag;
2131       newlink->tonode = link->tonode->new_node;
2132       newlink->tosock = link->tosock->new_sock;
2133       newlink->fromnode = link->fromnode->new_node;
2134       newlink->fromsock = link->fromsock->new_sock;
2135 
2136       BKE_node_clipboard_add_link(newlink);
2137     }
2138   }
2139 
2140   return OPERATOR_FINISHED;
2141 }
2142 
NODE_OT_clipboard_copy(wmOperatorType * ot)2143 void NODE_OT_clipboard_copy(wmOperatorType *ot)
2144 {
2145   /* identifiers */
2146   ot->name = "Copy to Clipboard";
2147   ot->description = "Copies selected nodes to the clipboard";
2148   ot->idname = "NODE_OT_clipboard_copy";
2149 
2150   /* api callbacks */
2151   ot->exec = node_clipboard_copy_exec;
2152   ot->poll = ED_operator_node_active;
2153 
2154   /* flags */
2155   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2156 }
2157 
2158 /* ****************** Paste from clipboard ******************* */
2159 
node_clipboard_paste_exec(bContext * C,wmOperator * op)2160 static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
2161 {
2162   SpaceNode *snode = CTX_wm_space_node(C);
2163   bNodeTree *ntree = snode->edittree;
2164   const ListBase *clipboard_nodes_lb;
2165   const ListBase *clipboard_links_lb;
2166   bNode *node;
2167   bNodeLink *link;
2168   int num_nodes;
2169   float center[2];
2170   bool is_clipboard_valid, all_nodes_valid;
2171 
2172   /* validate pointers in the clipboard */
2173   is_clipboard_valid = BKE_node_clipboard_validate();
2174   clipboard_nodes_lb = BKE_node_clipboard_get_nodes();
2175   clipboard_links_lb = BKE_node_clipboard_get_links();
2176 
2177   if (BLI_listbase_is_empty(clipboard_nodes_lb)) {
2178     BKE_report(op->reports, RPT_ERROR, "Clipboard is empty");
2179     return OPERATOR_CANCELLED;
2180   }
2181 
2182   if (BKE_node_clipboard_get_type() != ntree->type) {
2183     BKE_report(op->reports, RPT_ERROR, "Clipboard nodes are an incompatible type");
2184     return OPERATOR_CANCELLED;
2185   }
2186 
2187   /* only warn */
2188   if (is_clipboard_valid == false) {
2189     BKE_report(op->reports,
2190                RPT_WARNING,
2191                "Some nodes references could not be restored, will be left empty");
2192   }
2193 
2194   /* make sure all clipboard nodes would be valid in the target tree */
2195   all_nodes_valid = true;
2196   for (node = clipboard_nodes_lb->first; node; node = node->next) {
2197     if (!node->typeinfo->poll_instance || !node->typeinfo->poll_instance(node, ntree)) {
2198       all_nodes_valid = false;
2199       BKE_reportf(op->reports,
2200                   RPT_ERROR,
2201                   "Cannot add node %s into node tree %s",
2202                   node->name,
2203                   ntree->id.name + 2);
2204     }
2205   }
2206   if (!all_nodes_valid) {
2207     return OPERATOR_CANCELLED;
2208   }
2209 
2210   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2211 
2212   /* deselect old nodes */
2213   node_deselect_all(snode);
2214 
2215   /* calculate "barycenter" for placing on mouse cursor */
2216   zero_v2(center);
2217   for (node = clipboard_nodes_lb->first, num_nodes = 0; node; node = node->next, num_nodes++) {
2218     center[0] += BLI_rctf_cent_x(&node->totr);
2219     center[1] += BLI_rctf_cent_y(&node->totr);
2220   }
2221   mul_v2_fl(center, 1.0 / num_nodes);
2222 
2223   /* copy nodes from clipboard */
2224   for (node = clipboard_nodes_lb->first; node; node = node->next) {
2225     bNode *new_node = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
2226 
2227     /* pasted nodes are selected */
2228     nodeSetSelected(new_node, true);
2229   }
2230 
2231   /* reparent copied nodes */
2232   for (node = clipboard_nodes_lb->first; node; node = node->next) {
2233     bNode *new_node = node->new_node;
2234     if (new_node->parent) {
2235       new_node->parent = new_node->parent->new_node;
2236     }
2237   }
2238 
2239   for (link = clipboard_links_lb->first; link; link = link->next) {
2240     nodeAddLink(ntree,
2241                 link->fromnode->new_node,
2242                 link->fromsock->new_sock,
2243                 link->tonode->new_node,
2244                 link->tosock->new_sock);
2245   }
2246 
2247   ntreeUpdateTree(CTX_data_main(C), snode->edittree);
2248 
2249   snode_notify(C, snode);
2250   snode_dag_update(C, snode);
2251 
2252   return OPERATOR_FINISHED;
2253 }
2254 
NODE_OT_clipboard_paste(wmOperatorType * ot)2255 void NODE_OT_clipboard_paste(wmOperatorType *ot)
2256 {
2257   /* identifiers */
2258   ot->name = "Paste from Clipboard";
2259   ot->description = "Pastes nodes from the clipboard to the active node tree";
2260   ot->idname = "NODE_OT_clipboard_paste";
2261 
2262   /* api callbacks */
2263   ot->exec = node_clipboard_paste_exec;
2264   ot->poll = ED_operator_node_editable;
2265 
2266   /* flags */
2267   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2268 }
2269 
2270 /********************** Add interface socket operator *********************/
2271 
ntree_get_active_interface_socket(ListBase * lb)2272 static bNodeSocket *ntree_get_active_interface_socket(ListBase *lb)
2273 {
2274   bNodeSocket *sock;
2275   for (sock = lb->first; sock; sock = sock->next) {
2276     if (sock->flag & SELECT) {
2277       return sock;
2278     }
2279   }
2280   return NULL;
2281 }
2282 
ntree_socket_add_exec(bContext * C,wmOperator * op)2283 static int ntree_socket_add_exec(bContext *C, wmOperator *op)
2284 {
2285   SpaceNode *snode = CTX_wm_space_node(C);
2286   bNodeTree *ntree = snode->edittree;
2287   int in_out = RNA_enum_get(op->ptr, "in_out");
2288   PointerRNA ntree_ptr;
2289   bNodeSocket *sock, *tsock, *active_sock;
2290   const char *default_name;
2291 
2292   RNA_id_pointer_create((ID *)ntree, &ntree_ptr);
2293 
2294   if (in_out == SOCK_IN) {
2295     active_sock = ntree_get_active_interface_socket(&ntree->inputs);
2296     default_name = "Input";
2297   }
2298   else {
2299     active_sock = ntree_get_active_interface_socket(&ntree->outputs);
2300     default_name = "Output";
2301   }
2302 
2303   if (active_sock) {
2304     /* insert a copy of the active socket right after it */
2305     sock = ntreeInsertSocketInterface(
2306         ntree, in_out, active_sock->idname, active_sock->next, active_sock->name);
2307     /* XXX this only works for actual sockets, not interface templates! */
2308     /*nodeSocketCopyValue(sock, &ntree_ptr, active_sock, &ntree_ptr);*/
2309   }
2310   else {
2311     /* XXX TODO define default socket type for a tree! */
2312     sock = ntreeAddSocketInterface(ntree, in_out, "NodeSocketFloat", default_name);
2313   }
2314 
2315   /* deactivate sockets (has to check both lists) */
2316   for (tsock = ntree->inputs.first; tsock; tsock = tsock->next) {
2317     tsock->flag &= ~SELECT;
2318   }
2319   for (tsock = ntree->outputs.first; tsock; tsock = tsock->next) {
2320     tsock->flag &= ~SELECT;
2321   }
2322   /* make the new socket active */
2323   sock->flag |= SELECT;
2324 
2325   ntreeUpdateTree(CTX_data_main(C), ntree);
2326 
2327   snode_notify(C, snode);
2328   snode_dag_update(C, snode);
2329 
2330   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2331 
2332   return OPERATOR_FINISHED;
2333 }
2334 
NODE_OT_tree_socket_add(wmOperatorType * ot)2335 void NODE_OT_tree_socket_add(wmOperatorType *ot)
2336 {
2337   /* identifiers */
2338   ot->name = "Add Node Tree Interface Socket";
2339   ot->description = "Add an input or output socket to the current node tree";
2340   ot->idname = "NODE_OT_tree_socket_add";
2341 
2342   /* api callbacks */
2343   ot->exec = ntree_socket_add_exec;
2344   ot->poll = ED_operator_node_editable;
2345 
2346   /* flags */
2347   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2348 
2349   RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", "");
2350 }
2351 
2352 /********************** Remove interface socket operator *********************/
2353 
ntree_socket_remove_exec(bContext * C,wmOperator * UNUSED (op))2354 static int ntree_socket_remove_exec(bContext *C, wmOperator *UNUSED(op))
2355 {
2356   SpaceNode *snode = CTX_wm_space_node(C);
2357   bNodeTree *ntree = snode->edittree;
2358   bNodeSocket *iosock, *active_sock;
2359 
2360   iosock = ntree_get_active_interface_socket(&ntree->inputs);
2361   if (!iosock) {
2362     iosock = ntree_get_active_interface_socket(&ntree->outputs);
2363   }
2364   if (!iosock) {
2365     return OPERATOR_CANCELLED;
2366   }
2367 
2368   /* preferably next socket becomes active, otherwise try previous socket */
2369   active_sock = (iosock->next ? iosock->next : iosock->prev);
2370   ntreeRemoveSocketInterface(ntree, iosock);
2371 
2372   /* set active socket */
2373   if (active_sock) {
2374     active_sock->flag |= SELECT;
2375   }
2376 
2377   ntreeUpdateTree(CTX_data_main(C), ntree);
2378 
2379   snode_notify(C, snode);
2380   snode_dag_update(C, snode);
2381 
2382   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2383 
2384   return OPERATOR_FINISHED;
2385 }
2386 
NODE_OT_tree_socket_remove(wmOperatorType * ot)2387 void NODE_OT_tree_socket_remove(wmOperatorType *ot)
2388 {
2389   /* identifiers */
2390   ot->name = "Remove Node Tree Interface Socket";
2391   ot->description = "Remove an input or output socket to the current node tree";
2392   ot->idname = "NODE_OT_tree_socket_remove";
2393 
2394   /* api callbacks */
2395   ot->exec = ntree_socket_remove_exec;
2396   ot->poll = ED_operator_node_editable;
2397 
2398   /* flags */
2399   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2400 }
2401 
2402 /********************** Move interface socket operator *********************/
2403 
2404 static const EnumPropertyItem move_direction_items[] = {
2405     {1, "UP", 0, "Up", ""},
2406     {2, "DOWN", 0, "Down", ""},
2407     {0, NULL, 0, NULL, NULL},
2408 };
2409 
ntree_socket_move_exec(bContext * C,wmOperator * op)2410 static int ntree_socket_move_exec(bContext *C, wmOperator *op)
2411 {
2412   SpaceNode *snode = CTX_wm_space_node(C);
2413   bNodeTree *ntree = snode->edittree;
2414   int direction = RNA_enum_get(op->ptr, "direction");
2415   bNodeSocket *iosock;
2416   ListBase *lb;
2417 
2418   lb = &ntree->inputs;
2419   iosock = ntree_get_active_interface_socket(lb);
2420   if (!iosock) {
2421     lb = &ntree->outputs;
2422     iosock = ntree_get_active_interface_socket(lb);
2423   }
2424   if (!iosock) {
2425     return OPERATOR_CANCELLED;
2426   }
2427 
2428   switch (direction) {
2429     case 1: { /* up */
2430       bNodeSocket *before = iosock->prev;
2431       BLI_remlink(lb, iosock);
2432       if (before) {
2433         BLI_insertlinkbefore(lb, before, iosock);
2434       }
2435       else {
2436         BLI_addhead(lb, iosock);
2437       }
2438       break;
2439     }
2440     case 2: { /* down */
2441       bNodeSocket *after = iosock->next;
2442       BLI_remlink(lb, iosock);
2443       if (after) {
2444         BLI_insertlinkafter(lb, after, iosock);
2445       }
2446       else {
2447         BLI_addtail(lb, iosock);
2448       }
2449       break;
2450     }
2451   }
2452 
2453   ntree->update |= NTREE_UPDATE_GROUP;
2454   ntreeUpdateTree(CTX_data_main(C), ntree);
2455 
2456   snode_notify(C, snode);
2457   snode_dag_update(C, snode);
2458 
2459   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2460 
2461   return OPERATOR_FINISHED;
2462 }
2463 
NODE_OT_tree_socket_move(wmOperatorType * ot)2464 void NODE_OT_tree_socket_move(wmOperatorType *ot)
2465 {
2466   /* identifiers */
2467   ot->name = "Move Node Tree Socket";
2468   ot->description = "Move a socket up or down in the current node tree's sockets stack";
2469   ot->idname = "NODE_OT_tree_socket_move";
2470 
2471   /* api callbacks */
2472   ot->exec = ntree_socket_move_exec;
2473   ot->poll = ED_operator_node_editable;
2474 
2475   /* flags */
2476   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2477 
2478   RNA_def_enum(ot->srna, "direction", move_direction_items, 1, "Direction", "");
2479 }
2480 
2481 /* ********************** Shader Script Update ******************/
2482 
node_shader_script_update_poll(bContext * C)2483 static bool node_shader_script_update_poll(bContext *C)
2484 {
2485   Scene *scene = CTX_data_scene(C);
2486   const RenderEngineType *type = RE_engines_find(scene->r.engine);
2487   SpaceNode *snode = CTX_wm_space_node(C);
2488   bNode *node;
2489   Text *text;
2490 
2491   /* test if we have a render engine that supports shaders scripts */
2492   if (!(type && type->update_script_node)) {
2493     return 0;
2494   }
2495 
2496   /* see if we have a shader script node in context */
2497   node = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data;
2498 
2499   if (!node && snode && snode->edittree) {
2500     node = nodeGetActive(snode->edittree);
2501   }
2502 
2503   if (node && node->type == SH_NODE_SCRIPT) {
2504     NodeShaderScript *nss = node->storage;
2505 
2506     if (node->id || nss->filepath[0]) {
2507       return ED_operator_node_editable(C);
2508     }
2509   }
2510 
2511   /* see if we have a text datablock in context */
2512   text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data;
2513   if (text) {
2514     return 1;
2515   }
2516 
2517   /* we don't check if text datablock is actually in use, too slow for poll */
2518 
2519   return 0;
2520 }
2521 
2522 /* recursively check for script nodes in groups using this text and update */
node_shader_script_update_text_recursive(RenderEngine * engine,RenderEngineType * type,bNodeTree * ntree,Text * text)2523 static bool node_shader_script_update_text_recursive(RenderEngine *engine,
2524                                                      RenderEngineType *type,
2525                                                      bNodeTree *ntree,
2526                                                      Text *text)
2527 {
2528   bool found = false;
2529   bNode *node;
2530 
2531   ntree->done = true;
2532 
2533   /* update each script that is using this text datablock */
2534   for (node = ntree->nodes.first; node; node = node->next) {
2535     if (node->type == NODE_GROUP) {
2536       bNodeTree *ngroup = (bNodeTree *)node->id;
2537       if (ngroup && !ngroup->done) {
2538         found |= node_shader_script_update_text_recursive(engine, type, ngroup, text);
2539       }
2540     }
2541     else if (node->type == SH_NODE_SCRIPT && node->id == &text->id) {
2542       type->update_script_node(engine, ntree, node);
2543       found = true;
2544     }
2545   }
2546 
2547   return found;
2548 }
2549 
node_shader_script_update_exec(bContext * C,wmOperator * op)2550 static int node_shader_script_update_exec(bContext *C, wmOperator *op)
2551 {
2552   Main *bmain = CTX_data_main(C);
2553   Scene *scene = CTX_data_scene(C);
2554   SpaceNode *snode = CTX_wm_space_node(C);
2555   PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript);
2556   bNodeTree *ntree_base = NULL;
2557   bNode *node = NULL;
2558   RenderEngine *engine;
2559   RenderEngineType *type;
2560   bool found = false;
2561 
2562   /* setup render engine */
2563   type = RE_engines_find(scene->r.engine);
2564   engine = RE_engine_create(type);
2565   engine->reports = op->reports;
2566 
2567   /* get node */
2568   if (nodeptr.data) {
2569     ntree_base = (bNodeTree *)nodeptr.owner_id;
2570     node = nodeptr.data;
2571   }
2572   else if (snode && snode->edittree) {
2573     ntree_base = snode->edittree;
2574     node = nodeGetActive(snode->edittree);
2575   }
2576 
2577   if (node) {
2578     /* update single node */
2579     type->update_script_node(engine, ntree_base, node);
2580 
2581     found = true;
2582   }
2583   else {
2584     /* update all nodes using text datablock */
2585     Text *text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data;
2586 
2587     if (text) {
2588       /* clear flags for recursion check */
2589       FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
2590         if (ntree->type == NTREE_SHADER) {
2591           ntree->done = false;
2592         }
2593       }
2594       FOREACH_NODETREE_END;
2595 
2596       FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
2597         if (ntree->type == NTREE_SHADER) {
2598           if (!ntree->done) {
2599             found |= node_shader_script_update_text_recursive(engine, type, ntree, text);
2600           }
2601         }
2602       }
2603       FOREACH_NODETREE_END;
2604 
2605       if (!found) {
2606         BKE_report(op->reports, RPT_INFO, "Text not used by any node, no update done");
2607       }
2608     }
2609   }
2610 
2611   RE_engine_free(engine);
2612 
2613   return (found) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2614 }
2615 
NODE_OT_shader_script_update(wmOperatorType * ot)2616 void NODE_OT_shader_script_update(wmOperatorType *ot)
2617 {
2618   /* identifiers */
2619   ot->name = "Script Node Update";
2620   ot->description = "Update shader script node with new sockets and options from the script";
2621   ot->idname = "NODE_OT_shader_script_update";
2622 
2623   /* api callbacks */
2624   ot->exec = node_shader_script_update_exec;
2625   ot->poll = node_shader_script_update_poll;
2626 
2627   /* flags */
2628   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2629 }
2630 
2631 /* ********************** Viewer border ******************/
2632 
viewer_border_corner_to_backdrop(SpaceNode * snode,ARegion * region,int x,int y,int backdrop_width,int backdrop_height,float * fx,float * fy)2633 static void viewer_border_corner_to_backdrop(SpaceNode *snode,
2634                                              ARegion *region,
2635                                              int x,
2636                                              int y,
2637                                              int backdrop_width,
2638                                              int backdrop_height,
2639                                              float *fx,
2640                                              float *fy)
2641 {
2642   float bufx, bufy;
2643 
2644   bufx = backdrop_width * snode->zoom;
2645   bufy = backdrop_height * snode->zoom;
2646 
2647   *fx = (bufx > 0.0f ? ((float)x - 0.5f * region->winx - snode->xof) / bufx + 0.5f : 0.0f);
2648   *fy = (bufy > 0.0f ? ((float)y - 0.5f * region->winy - snode->yof) / bufy + 0.5f : 0.0f);
2649 }
2650 
viewer_border_exec(bContext * C,wmOperator * op)2651 static int viewer_border_exec(bContext *C, wmOperator *op)
2652 {
2653   Main *bmain = CTX_data_main(C);
2654   Image *ima;
2655   void *lock;
2656   ImBuf *ibuf;
2657 
2658   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
2659 
2660   ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
2661   ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
2662 
2663   if (ibuf) {
2664     ARegion *region = CTX_wm_region(C);
2665     SpaceNode *snode = CTX_wm_space_node(C);
2666     bNodeTree *btree = snode->nodetree;
2667     rcti rect;
2668     rctf rectf;
2669 
2670     /* get border from operator */
2671     WM_operator_properties_border_to_rcti(op, &rect);
2672 
2673     /* convert border to unified space within backdrop image */
2674     viewer_border_corner_to_backdrop(
2675         snode, region, rect.xmin, rect.ymin, ibuf->x, ibuf->y, &rectf.xmin, &rectf.ymin);
2676 
2677     viewer_border_corner_to_backdrop(
2678         snode, region, rect.xmax, rect.ymax, ibuf->x, ibuf->y, &rectf.xmax, &rectf.ymax);
2679 
2680     /* clamp coordinates */
2681     rectf.xmin = max_ff(rectf.xmin, 0.0f);
2682     rectf.ymin = max_ff(rectf.ymin, 0.0f);
2683     rectf.xmax = min_ff(rectf.xmax, 1.0f);
2684     rectf.ymax = min_ff(rectf.ymax, 1.0f);
2685 
2686     if (rectf.xmin < rectf.xmax && rectf.ymin < rectf.ymax) {
2687       btree->viewer_border = rectf;
2688 
2689       if (rectf.xmin == 0.0f && rectf.ymin == 0.0f && rectf.xmax == 1.0f && rectf.ymax == 1.0f) {
2690         btree->flag &= ~NTREE_VIEWER_BORDER;
2691       }
2692       else {
2693         btree->flag |= NTREE_VIEWER_BORDER;
2694       }
2695 
2696       snode_notify(C, snode);
2697       WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2698     }
2699     else {
2700       btree->flag &= ~NTREE_VIEWER_BORDER;
2701     }
2702   }
2703 
2704   BKE_image_release_ibuf(ima, ibuf, lock);
2705 
2706   return OPERATOR_FINISHED;
2707 }
2708 
NODE_OT_viewer_border(wmOperatorType * ot)2709 void NODE_OT_viewer_border(wmOperatorType *ot)
2710 {
2711   /* identifiers */
2712   ot->name = "Viewer Region";
2713   ot->description = "Set the boundaries for viewer operations";
2714   ot->idname = "NODE_OT_viewer_border";
2715 
2716   /* api callbacks */
2717   ot->invoke = WM_gesture_box_invoke;
2718   ot->exec = viewer_border_exec;
2719   ot->modal = WM_gesture_box_modal;
2720   ot->cancel = WM_gesture_box_cancel;
2721   ot->poll = composite_node_active;
2722 
2723   /* flags */
2724   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2725 
2726   /* properties */
2727   WM_operator_properties_gesture_box(ot);
2728 }
2729 
clear_viewer_border_exec(bContext * C,wmOperator * UNUSED (op))2730 static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
2731 {
2732   SpaceNode *snode = CTX_wm_space_node(C);
2733   bNodeTree *btree = snode->nodetree;
2734 
2735   btree->flag &= ~NTREE_VIEWER_BORDER;
2736   snode_notify(C, snode);
2737   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2738 
2739   return OPERATOR_FINISHED;
2740 }
2741 
NODE_OT_clear_viewer_border(wmOperatorType * ot)2742 void NODE_OT_clear_viewer_border(wmOperatorType *ot)
2743 {
2744   /* identifiers */
2745   ot->name = "Clear Viewer Region";
2746   ot->description = "Clear the boundaries for viewer operations";
2747   ot->idname = "NODE_OT_clear_viewer_border";
2748 
2749   /* api callbacks */
2750   ot->exec = clear_viewer_border_exec;
2751   ot->poll = composite_node_active;
2752 
2753   /* flags */
2754   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2755 }
2756 
2757 /* ****************** Cryptomatte Add Socket  ******************* */
2758 
node_cryptomatte_add_socket_exec(bContext * C,wmOperator * UNUSED (op))2759 static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
2760 {
2761   SpaceNode *snode = CTX_wm_space_node(C);
2762   PointerRNA ptr = CTX_data_pointer_get(C, "node");
2763   bNodeTree *ntree = NULL;
2764   bNode *node = NULL;
2765 
2766   if (ptr.data) {
2767     node = ptr.data;
2768     ntree = (bNodeTree *)ptr.owner_id;
2769   }
2770   else if (snode && snode->edittree) {
2771     ntree = snode->edittree;
2772     node = nodeGetActive(snode->edittree);
2773   }
2774 
2775   if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
2776     return OPERATOR_CANCELLED;
2777   }
2778 
2779   ntreeCompositCryptomatteAddSocket(ntree, node);
2780 
2781   snode_notify(C, snode);
2782 
2783   return OPERATOR_FINISHED;
2784 }
2785 
NODE_OT_cryptomatte_layer_add(wmOperatorType * ot)2786 void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot)
2787 {
2788   /* identifiers */
2789   ot->name = "Add Cryptomatte Socket";
2790   ot->description = "Add a new input layer to a Cryptomatte node";
2791   ot->idname = "NODE_OT_cryptomatte_layer_add";
2792 
2793   /* callbacks */
2794   ot->exec = node_cryptomatte_add_socket_exec;
2795   ot->poll = composite_node_editable;
2796 
2797   /* flags */
2798   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2799 }
2800 
2801 /* ****************** Cryptomatte Remove Socket  ******************* */
2802 
node_cryptomatte_remove_socket_exec(bContext * C,wmOperator * UNUSED (op))2803 static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(op))
2804 {
2805   SpaceNode *snode = CTX_wm_space_node(C);
2806   PointerRNA ptr = CTX_data_pointer_get(C, "node");
2807   bNodeTree *ntree = NULL;
2808   bNode *node = NULL;
2809 
2810   if (ptr.data) {
2811     node = ptr.data;
2812     ntree = (bNodeTree *)ptr.owner_id;
2813   }
2814   else if (snode && snode->edittree) {
2815     ntree = snode->edittree;
2816     node = nodeGetActive(snode->edittree);
2817   }
2818 
2819   if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
2820     return OPERATOR_CANCELLED;
2821   }
2822 
2823   if (!ntreeCompositCryptomatteRemoveSocket(ntree, node)) {
2824     return OPERATOR_CANCELLED;
2825   }
2826 
2827   snode_notify(C, snode);
2828 
2829   return OPERATOR_FINISHED;
2830 }
2831 
NODE_OT_cryptomatte_layer_remove(wmOperatorType * ot)2832 void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot)
2833 {
2834   /* identifiers */
2835   ot->name = "Remove Cryptomatte Socket";
2836   ot->description = "Remove layer from a Cryptomatte node";
2837   ot->idname = "NODE_OT_cryptomatte_layer_remove";
2838 
2839   /* callbacks */
2840   ot->exec = node_cryptomatte_remove_socket_exec;
2841   ot->poll = composite_node_editable;
2842 
2843   /* flags */
2844   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2845 }
2846