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(®ion->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(®ion->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