Blender V4.3
node_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10
11#include "MEM_guardedalloc.h"
12
13#include "DNA_material_types.h"
14#include "DNA_node_types.h"
15#include "DNA_text_types.h"
16#include "DNA_world_types.h"
17
18#include "BKE_callbacks.hh"
19#include "BKE_context.hh"
20#include "BKE_global.hh"
21#include "BKE_image.hh"
22#include "BKE_lib_id.hh"
23#include "BKE_main.hh"
24#include "BKE_material.h"
25#include "BKE_node.hh"
26#include "BKE_node_runtime.hh"
28#include "BKE_report.hh"
29#include "BKE_scene.hh"
30#include "BKE_scene_runtime.hh"
31
32#include "BLI_string.h"
33#include "BLI_string_utf8.h"
34
35#include "BLT_translation.hh"
36
37#include "DEG_depsgraph.hh"
41
42#include "RE_engine.h"
43#include "RE_pipeline.h"
44
45#include "ED_image.hh"
46#include "ED_node.hh" /* own include */
47#include "ED_render.hh"
48#include "ED_screen.hh"
49#include "ED_viewer_path.hh"
50
51#include "RNA_access.hh"
52#include "RNA_define.hh"
53#include "RNA_prototypes.hh"
54
55#include "WM_api.hh"
56#include "WM_types.hh"
57
58#include "UI_view2d.hh"
59
60#include "GPU_capabilities.hh"
61#include "GPU_material.hh"
62
63#include "IMB_imbuf_types.hh"
64
65#include "NOD_composite.hh"
66#include "NOD_geometry.hh"
67#include "NOD_shader.h"
68#include "NOD_socket.hh"
69#include "NOD_texture.h"
70#include "node_intern.hh" /* own include */
71
72#include "COM_profiler.hh"
73
75
76#define USE_ESC_COMPO
77
78/* -------------------------------------------------------------------- */
82enum {
85};
86
87struct CompoJob {
88 /* Input parameters. */
94 /* Evaluated state/ */
97 /* Render instance. */
99 /* Job system integration. */
100 const bool *stop;
102 float *progress;
104
106};
107
109{
110 float sock_height = NODE_SOCKSIZE * NODE_SOCKSIZE_DRAW_MULIPLIER;
111 if (socket.flag & SOCK_MULTI_INPUT) {
112 sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket.runtime->total_inputs,
114 }
115 return sock_height;
116}
117
119 const int index,
120 const int total_inputs)
121{
122 const float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) *
123 0.5f;
124 return {socket_position.x, socket_position.y - offset + index * NODE_MULTI_INPUT_LINK_GAP};
125}
126
127static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
128{
129 for (bNode *node : nodetree->all_nodes()) {
130 if (node->type == CMP_NODE_COMPOSITE) {
131 if (recalc_flags & COM_RECALC_COMPOSITE) {
132 node->flag |= NODE_DO_OUTPUT_RECALC;
133 }
134 }
135 else if (node->type == CMP_NODE_VIEWER) {
136 if (recalc_flags & COM_RECALC_VIEWER) {
137 node->flag |= NODE_DO_OUTPUT_RECALC;
138 }
139 }
140 else if (node->type == NODE_GROUP) {
141 if (node->id) {
142 compo_tag_output_nodes((bNodeTree *)node->id, recalc_flags);
143 }
144 }
145 }
146}
147
149{
151 int recalc_flags = 0;
152
153 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
154 const bScreen *screen = WM_window_get_active_screen(win);
155
156 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
157 if (area->spacetype == SPACE_IMAGE) {
158 SpaceImage *sima = (SpaceImage *)area->spacedata.first;
159 if (sima->image) {
160 if (sima->image->type == IMA_TYPE_R_RESULT) {
161 recalc_flags |= COM_RECALC_COMPOSITE;
162 }
163 else if (sima->image->type == IMA_TYPE_COMPOSITE) {
164 recalc_flags |= COM_RECALC_VIEWER;
165 }
166 }
167 }
168 else if (area->spacetype == SPACE_NODE) {
169 SpaceNode *snode = (SpaceNode *)area->spacedata.first;
170 if (snode->flag & SNODE_BACKDRAW) {
171 recalc_flags |= COM_RECALC_VIEWER;
172 }
173 }
174 }
175 }
176
177 return recalc_flags;
178}
179
180/* Called by compositor, only to check job 'stop' value. */
181static bool compo_breakjob(void *cjv)
182{
183 CompoJob *cj = (CompoJob *)cjv;
184
185 /* Without G.is_break 'ESC' won't quit - which annoys users. */
186 return (*(cj->stop)
187#ifdef USE_ESC_COMPO
188 || G.is_break
189#endif
190 );
191}
192
193/* Called by compositor, #wmJob sends notifier. */
194static void compo_statsdrawjob(void *cjv, const char * /*str*/)
195{
196 CompoJob *cj = (CompoJob *)cjv;
197
198 *(cj->do_update) = true;
199}
200
201/* Called by compositor, wmJob sends notifier. */
202static void compo_redrawjob(void *cjv)
203{
204 CompoJob *cj = (CompoJob *)cjv;
205
206 *(cj->do_update) = true;
207}
208
209static void compo_freejob(void *cjv)
210{
211 CompoJob *cj = (CompoJob *)cjv;
212
213 if (cj->localtree) {
214 /* Merge back node previews, only for completed jobs. */
215 if (!cj->cancelled) {
217 }
218
220 MEM_freeN(cj->localtree);
221 }
222
223 MEM_delete(cj);
224}
225
226/* Only now we copy the nodetree, so adding many jobs while
227 * sliding buttons doesn't frustrate. */
228static void compo_initjob(void *cjv)
229{
230 CompoJob *cj = (CompoJob *)cjv;
231 Main *bmain = cj->bmain;
232 Scene *scene = cj->scene;
233 ViewLayer *view_layer = cj->view_layer;
234
235 bke::CompositorRuntime &compositor_runtime = scene->runtime->compositor;
236
237 if (!compositor_runtime.preview_depsgraph) {
238 compositor_runtime.preview_depsgraph = DEG_graph_new(
239 bmain, scene, view_layer, DAG_EVAL_RENDER);
240 DEG_debug_name_set(compositor_runtime.preview_depsgraph, "COMPOSITOR");
241 }
242
243 cj->compositor_depsgraph = compositor_runtime.preview_depsgraph;
245
246 /* NOTE: Don't update animation to preserve unkeyed changes, this means can not use
247 * evaluate_on_framechange. */
249
251 &cj->ntree->id);
252
253 cj->localtree = bke::node_tree_localize(ntree_eval, nullptr);
254
255 if (cj->recalc_flags) {
257 }
258
260 if (scene->r.compositor_device == SCE_COMPOSITOR_DEVICE_GPU) {
262 }
263}
264
265/* Called before redraw notifiers, it moves finished previews over. */
266static void compo_updatejob(void * /*cjv*/)
267{
269}
270
271static void compo_progressjob(void *cjv, float progress)
272{
273 CompoJob *cj = (CompoJob *)cjv;
274
275 *(cj->progress) = progress;
276}
277
278/* Only this runs inside thread. */
279static void compo_startjob(void *cjv, wmJobWorkerStatus *worker_status)
280{
281 CompoJob *cj = (CompoJob *)cjv;
282 bNodeTree *ntree = cj->localtree;
284
285 if (scene->use_nodes == false) {
286 return;
287 }
288
289 cj->stop = &worker_status->stop;
290 cj->do_update = &worker_status->do_update;
291 cj->progress = &worker_status->progress;
292
293 ntree->runtime->test_break = compo_breakjob;
294 ntree->runtime->tbh = cj;
295 ntree->runtime->stats_draw = compo_statsdrawjob;
296 ntree->runtime->sdh = cj;
297 ntree->runtime->progress = compo_progressjob;
298 ntree->runtime->prh = cj;
299 ntree->runtime->update_draw = compo_redrawjob;
300 ntree->runtime->udh = cj;
301
303
304 if ((scene->r.scemode & R_MULTIVIEW) == 0) {
305 ntreeCompositExecTree(cj->re, scene, ntree, &scene->r, "", nullptr, &cj->profiler);
306 }
307 else {
308 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
309 if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) {
310 continue;
311 }
312 ntreeCompositExecTree(cj->re, scene, ntree, &scene->r, srv->name, nullptr, &cj->profiler);
313 }
314 }
315
316 ntree->runtime->test_break = nullptr;
317 ntree->runtime->stats_draw = nullptr;
318 ntree->runtime->progress = nullptr;
319}
320
321static void compo_canceljob(void *cjv)
322{
323 CompoJob *cj = (CompoJob *)cjv;
324 Main *bmain = cj->bmain;
325 Scene *scene = cj->scene;
327 cj->cancelled = true;
328
329 scene->runtime->compositor.per_node_execution_time = cj->profiler.get_nodes_evaluation_times();
330}
331
332static void compo_completejob(void *cjv)
333{
334 CompoJob *cj = (CompoJob *)cjv;
335 Main *bmain = cj->bmain;
336 Scene *scene = cj->scene;
338
339 scene->runtime->compositor.per_node_execution_time = cj->profiler.get_nodes_evaluation_times();
340}
341
344} // namespace blender::ed::space_node
345
346/* -------------------------------------------------------------------- */
350/* Identify if the compositor can run. Currently, this only checks if the compositor is set to GPU
351 * and the render size exceeds what can be allocated as a texture in it. */
353{
354 Scene *scene = CTX_data_scene(C);
355 /* CPU compositor can always run. */
356 if (scene->r.compositor_device != SCE_COMPOSITOR_DEVICE_GPU) {
357 return true;
358 }
359
360 int width, height;
361 BKE_render_resolution(&scene->r, false, &width, &height);
362 const int max_texture_size = GPU_max_texture_size();
363
364 /* There is no way to know if the render size is too large except if we actually allocate a test
365 * texture, which we want to avoid due its cost. So we employ a heuristic that so far has worked
366 * with all known GPU drivers. */
367 if (size_t(width) * height > (size_t(max_texture_size) * max_texture_size) / 4) {
368 WM_report(RPT_ERROR, "Render size too large for GPU, use CPU compositor instead");
369 return false;
370 }
371
372 return true;
373}
374
375void ED_node_composite_job(const bContext *C, bNodeTree *nodetree, Scene *scene_owner)
376{
377 using namespace blender::ed::space_node;
378
379 Main *bmain = CTX_data_main(C);
380 Scene *scene = CTX_data_scene(C);
381 ViewLayer *view_layer = CTX_data_view_layer(C);
382
383 if (!is_compositing_possible(C)) {
384 return;
385 }
386
387 /* See #32272. */
388 if (G.is_rendering) {
389 return;
390 }
391
392#ifdef USE_ESC_COMPO
393 G.is_break = false;
394#endif
395
397 scene, BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"), false);
398
399 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
400 CTX_wm_window(C),
401 scene_owner,
402 "Compositing",
405 CompoJob *cj = MEM_new<CompoJob>("compo job");
406
407 /* Custom data for preview thread. */
408 cj->bmain = bmain;
409 cj->scene = scene;
410 cj->view_layer = view_layer;
411 cj->ntree = nodetree;
412 cj->recalc_flags = compo_get_recalc_flags(C);
413
414 /* Set up job. */
415 WM_jobs_customdata_set(wm_job, cj, compo_freejob);
418 compo_startjob,
419 compo_initjob,
420 compo_updatejob,
421 nullptr,
422 compo_completejob,
423 compo_canceljob);
424
425 WM_jobs_start(CTX_wm_manager(C), wm_job);
426}
427
430namespace blender::ed::space_node {
431
432/* -------------------------------------------------------------------- */
437{
439 SpaceNode *snode = CTX_wm_space_node(C);
440 if (ED_node_is_compositor(snode)) {
441 return true;
442 }
443 }
444 return false;
445}
446
448{
450 SpaceNode *snode = CTX_wm_space_node(C);
451 if (ED_node_is_compositor(snode)) {
452 return true;
453 }
454 }
455 return false;
456}
457
459{
461
462 if (ntree->type == NTREE_SHADER && id != nullptr) {
463 if (GS(id->name) == ID_MA) {
465 }
466 else if (GS(id->name) == ID_LA) {
468 }
469 else if (GS(id->name) == ID_WO) {
471 }
472 }
473 else if (ntree->type == NTREE_COMPOSIT) {
475 }
476 else if (ntree->type == NTREE_TEXTURE) {
478 }
479 else if (ntree->type == NTREE_GEOMETRY) {
481 }
482}
483
486} // namespace blender::ed::space_node
487
488/* -------------------------------------------------------------------- */
492void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree)
493{
494 if (C != nullptr) {
495 SpaceNode *snode = CTX_wm_space_node(C);
496 if (snode != nullptr && root_ntree != nullptr) {
498 }
499 }
500
502 params.tree_changed_fn = [](ID *id, bNodeTree *ntree, void * /*user_data*/) {
505 };
506 params.tree_output_changed_fn = [](ID * /*id*/, bNodeTree *ntree, void * /*user_data*/) {
508 };
509
510 BKE_ntree_update_main_tree(bmain, root_ntree, &params);
511}
512
514{
515 if (typeinfo) {
516 STRNCPY(snode->tree_idname, typeinfo->idname);
517 }
518 else {
519 snode->tree_idname[0] = '\0';
520 }
521}
522
524{
526}
527
529{
530 return STREQ(snode->tree_idname, ntreeType_Shader->idname);
531}
532
534{
535 return STREQ(snode->tree_idname, ntreeType_Texture->idname);
536}
537
539{
541}
542
544{
545 return ED_node_is_compositor(snode) ||
546 (U.experimental.use_shader_node_previews && ED_node_is_shader(snode));
547}
548
550{
551 Main *bmain = CTX_data_main(C);
552
553 if (GS(id->name) == ID_MA) {
554 /* Materials */
556 Material *ma = (Material *)id;
557 Material *ma_default;
558
559 if (ob && ob->type == OB_VOLUME) {
560 ma_default = BKE_material_default_volume();
561 }
562 else {
563 ma_default = BKE_material_default_surface();
564 }
565
566 ma->nodetree = blender::bke::node_tree_copy_tree(bmain, ma_default->nodetree);
567 ma->nodetree->owner_id = &ma->id;
568 for (bNode *node_iter : ma->nodetree->all_nodes()) {
569 STRNCPY_UTF8(node_iter->name, DATA_(node_iter->name));
571 }
572
573 BKE_ntree_update_main_tree(bmain, ma->nodetree, nullptr);
574 }
575 else if (ELEM(GS(id->name), ID_WO, ID_LA)) {
576 /* Emission */
578 nullptr, id, "Shader Nodetree", ntreeType_Shader->idname);
579 bNode *shader, *output;
580
581 if (GS(id->name) == ID_WO) {
582 World *world = (World *)id;
583
584 shader = blender::bke::node_add_static_node(nullptr, ntree, SH_NODE_BACKGROUND);
587 shader,
588 blender::bke::node_find_socket(shader, SOCK_OUT, "Background"),
589 output,
590 blender::bke::node_find_socket(output, SOCK_IN, "Surface"));
591
592 bNodeSocket *color_sock = blender::bke::node_find_socket(shader, SOCK_IN, "Color");
593 copy_v3_v3(((bNodeSocketValueRGBA *)color_sock->default_value)->value, &world->horr);
594 }
595 else {
596 shader = blender::bke::node_add_static_node(nullptr, ntree, SH_NODE_EMISSION);
599 shader,
600 blender::bke::node_find_socket(shader, SOCK_OUT, "Emission"),
601 output,
602 blender::bke::node_find_socket(output, SOCK_IN, "Surface"));
603 }
604
605 shader->locx = 10.0f;
606 shader->locy = 300.0f;
607 output->locx = 300.0f;
608 output->locy = 300.0f;
609 blender::bke::node_set_active(ntree, output);
610 BKE_ntree_update_main_tree(bmain, ntree, nullptr);
611 }
612 else {
613 printf("ED_node_shader_default called on wrong ID type.\n");
614 return;
615 }
616}
617
619{
620 /* but lets check it anyway */
621 if (sce->nodetree) {
622 if (G.debug & G_DEBUG) {
623 printf("error in composite initialize\n");
624 }
625 return;
626 }
627
629 nullptr, &sce->id, "Compositing Nodetree", ntreeType_Composite->idname);
630
631 bNode *out = blender::bke::node_add_static_node(C, sce->nodetree, CMP_NODE_COMPOSITE);
632 out->locx = 200.0f;
633 out->locy = 200.0f;
634
635 bNode *in = blender::bke::node_add_static_node(C, sce->nodetree, CMP_NODE_R_LAYERS);
636 in->locx = -200.0f;
637 in->locy = 200.0f;
639
640 /* Links from color to color. */
641 bNodeSocket *fromsock = (bNodeSocket *)in->outputs.first;
642 bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
643 blender::bke::node_add_link(sce->nodetree, in, fromsock, out, tosock);
644
646}
647
649{
650 if (tex->nodetree) {
651 if (G.debug & G_DEBUG) {
652 printf("error in texture initialize\n");
653 }
654 return;
655 }
656
658 nullptr, &tex->id, "Texture Nodetree", ntreeType_Texture->idname);
659
660 bNode *out = blender::bke::node_add_static_node(C, tex->nodetree, TEX_NODE_OUTPUT);
661 out->locx = 300.0f;
662 out->locy = 300.0f;
663
664 bNode *in = blender::bke::node_add_static_node(C, tex->nodetree, TEX_NODE_CHECKER);
665 in->locx = 10.0f;
666 in->locy = 300.0f;
668
669 bNodeSocket *fromsock = (bNodeSocket *)in->outputs.first;
670 bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
671 blender::bke::node_add_link(tex->nodetree, in, fromsock, out, tosock);
672
674}
675
676namespace blender::ed::space_node {
677
679{
680 /* NOTE: Here we set the active tree(s), even called for each redraw now, so keep it fast :). */
681
682 SpaceNode *snode = CTX_wm_space_node(&C);
684 bNodeTree *ntree = snode->nodetree;
685 ID *id = snode->id, *from = snode->from;
686
687 /* Check the tree type. */
688 if (!treetype || (treetype->poll && !treetype->poll(&C, treetype))) {
689 /* Invalid tree type, skip.
690 * NOTE: not resetting the node path here, invalid #bNodeTreeType
691 * may still be registered at a later point. */
692 return;
693 }
694
695 if (snode->nodetree && !STREQ(snode->nodetree->idname, snode->tree_idname)) {
696 /* Current tree does not match selected type, clear tree path. */
697 ntree = nullptr;
698 id = nullptr;
699 from = nullptr;
700 }
701
702 if (!(snode->flag & SNODE_PIN) || ntree == nullptr) {
703 if (treetype->get_from_context) {
704 /* Reset and update from context. */
705 ntree = nullptr;
706 id = nullptr;
707 from = nullptr;
708
709 treetype->get_from_context(&C, treetype, &ntree, &id, &from);
710 }
711 }
712
713 if (snode->nodetree != ntree || snode->id != id || snode->from != from ||
714 (snode->treepath.last == nullptr && ntree))
715 {
716 ED_node_tree_start(snode, ntree, id, from);
717 }
718}
719
720} // namespace blender::ed::space_node
721
723 Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
724{
725 const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0;
726 if (r_active_texture_changed) {
727 *r_active_texture_changed = false;
728 }
729
731 if (node->type == NODE_GROUP) {
732 return;
733 }
734
735 const bool was_output = (node->flag & NODE_DO_OUTPUT) != 0;
736 bool do_update = false;
737
738 /* Generic node group output: set node as active output. */
739 if (node->type == NODE_GROUP_OUTPUT) {
740 for (bNode *node_iter : ntree->all_nodes()) {
741 if (node_iter->type == NODE_GROUP_OUTPUT) {
742 node_iter->flag &= ~NODE_DO_OUTPUT;
743 }
744 }
745
746 node->flag |= NODE_DO_OUTPUT;
747 if (!was_output) {
748 do_update = true;
750 }
751 }
752
753 /* Tree specific activate calls. */
754 if (ntree->type == NTREE_SHADER) {
755 if (ELEM(node->type,
760 {
761 for (bNode *node_iter : ntree->all_nodes()) {
762 if (node_iter->type == node->type) {
763 node_iter->flag &= ~NODE_DO_OUTPUT;
764 }
765 }
766
767 node->flag |= NODE_DO_OUTPUT;
769 }
770
771 ED_node_tree_propagate_change(nullptr, bmain, ntree);
772
773 if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
774 /* If active texture changed, free GLSL materials. */
775 LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
776 if (ma->nodetree && ma->use_nodes &&
777 blender::bke::node_tree_contains_tree(ma->nodetree, ntree))
778 {
779 GPU_material_free(&ma->gpumaterial);
780
781 /* Sync to active texpaint slot, otherwise we can end up painting on a different slot
782 * than we are looking at. */
783 if (ma->texpaintslot) {
784 if (node->id != nullptr && GS(node->id->name) == ID_IM) {
785 Image *image = (Image *)node->id;
786 for (int i = 0; i < ma->tot_slots; i++) {
787 if (ma->texpaintslot[i].ima == image) {
788 ma->paint_active_slot = i;
789 }
790 }
791 }
792 }
793 }
794 }
795
796 LISTBASE_FOREACH (World *, wo, &bmain->worlds) {
797 if (wo->nodetree && wo->use_nodes &&
798 blender::bke::node_tree_contains_tree(wo->nodetree, ntree))
799 {
800 GPU_material_free(&wo->gpumaterial);
801 }
802 }
803
804 /* Sync to Image Editor under the following conditions:
805 * - current image is not pinned
806 * - current image is not a Render Result or ViewerNode (want to keep looking at these) */
807 if (node->id != nullptr && GS(node->id->name) == ID_IM) {
808 Image *image = (Image *)node->id;
809 ED_space_image_sync(bmain, image, true);
810 }
811
812 if (r_active_texture_changed) {
813 *r_active_texture_changed = true;
814 }
815 ED_node_tree_propagate_change(nullptr, bmain, ntree);
817 }
818
820 }
821 else if (ntree->type == NTREE_COMPOSIT) {
822 /* Make active viewer, currently only one is supported. */
823 if (node->type == CMP_NODE_VIEWER) {
824 for (bNode *node_iter : ntree->all_nodes()) {
825 if (node_iter->type == CMP_NODE_VIEWER) {
826 node_iter->flag &= ~NODE_DO_OUTPUT;
827 }
828 }
829
830 node->flag |= NODE_DO_OUTPUT;
831 if (was_output == 0) {
833 ED_node_tree_propagate_change(nullptr, bmain, ntree);
834 }
835
836 /* Adding a node doesn't link this yet. */
837 node->id = (ID *)BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
838 }
839 else if (node->type == CMP_NODE_COMPOSITE) {
840 if (was_output == 0) {
841 for (bNode *node_iter : ntree->all_nodes()) {
842 if (node_iter->type == CMP_NODE_COMPOSITE) {
843 node_iter->flag &= ~NODE_DO_OUTPUT;
844 }
845 }
846
847 node->flag |= NODE_DO_OUTPUT;
849 ED_node_tree_propagate_change(nullptr, bmain, ntree);
850 }
851 }
852 else if (do_update) {
853 ED_node_tree_propagate_change(nullptr, bmain, ntree);
854 }
855 }
856 else if (ntree->type == NTREE_GEOMETRY) {
857 if (node->type == GEO_NODE_VIEWER) {
858 if ((node->flag & NODE_DO_OUTPUT) == 0) {
859 for (bNode *node_iter : ntree->all_nodes()) {
860 if (node_iter->type == GEO_NODE_VIEWER) {
861 node_iter->flag &= ~NODE_DO_OUTPUT;
862 }
863 }
864 node->flag |= NODE_DO_OUTPUT;
865 }
867 }
868 }
869}
870
872{
873 /* XXX This does not work due to layout functions relying on node->block,
874 * which only exists during actual drawing. Can we rely on valid totr rects?
875 */
876 /* make sure nodes have correct bounding boxes after transform */
877 // node_update_nodetree(C, ntree, 0.0f, 0.0f);
878}
879
882namespace blender::ed::space_node {
883
884/* -------------------------------------------------------------------- */
888static bool socket_is_occluded(const float2 &location,
889 const bNode &node_the_socket_belongs_to,
890 const Span<bNode *> sorted_nodes)
891{
892 for (bNode *node : sorted_nodes) {
893 if (node == &node_the_socket_belongs_to) {
894 /* Nodes after this one are underneath and can't occlude the socket. */
895 return false;
896 }
897
898 rctf socket_hitbox;
899 const float socket_hitbox_radius = NODE_SOCKSIZE - 0.1f * U.widget_unit;
900 BLI_rctf_init_pt_radius(&socket_hitbox, location, socket_hitbox_radius);
901 if (BLI_rctf_inside_rctf(&node->runtime->totr, &socket_hitbox)) {
902 return true;
903 }
904 }
905 return false;
906}
907
910/* -------------------------------------------------------------------- */
921
923 bContext *C, wmOperator *op, const float2 &cursor, const bNode *node, NodeResizeDirection dir)
924{
925 NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__);
926
927 op->customdata = nsw;
928
929 nsw->mxstart = cursor.x;
930 nsw->mystart = cursor.y;
931
932 /* store old */
933 nsw->oldlocx = node->locx;
934 nsw->oldlocy = node->locy;
935 nsw->oldoffsetx = node->offsetx;
936 nsw->oldoffsety = node->offsety;
937 nsw->oldwidth = node->width;
938 nsw->oldheight = node->height;
939 nsw->directions = dir;
940
942 /* add modal handler */
944}
945
946static void node_resize_exit(bContext *C, wmOperator *op, bool cancel)
947{
949
950 /* Restore old data on cancel. */
951 if (cancel) {
952 SpaceNode *snode = CTX_wm_space_node(C);
953 bNode *node = bke::node_get_active(snode->edittree);
955
956 node->locx = nsw->oldlocx;
957 node->locy = nsw->oldlocy;
958 node->offsetx = nsw->oldoffsetx;
959 node->offsety = nsw->oldoffsety;
960 node->width = nsw->oldwidth;
961 node->height = nsw->oldheight;
962 }
963
965 op->customdata = nullptr;
966}
967
968static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
969{
970 SpaceNode *snode = CTX_wm_space_node(C);
971 ARegion *region = CTX_wm_region(C);
972 bNode *node = bke::node_get_active(snode->edittree);
974
975 switch (event->type) {
976 case MOUSEMOVE: {
977 int2 mval;
978 WM_event_drag_start_mval(event, region, mval);
979 float mx, my;
980 UI_view2d_region_to_view(&region->v2d, mval.x, mval.y, &mx, &my);
981 const float dx = (mx - nsw->mxstart) / UI_SCALE_FAC;
982 const float dy = (my - nsw->mystart) / UI_SCALE_FAC;
983
984 if (node) {
985 float *pwidth = &node->width;
986 float oldwidth = nsw->oldwidth;
987 float widthmin = node->typeinfo->minwidth;
988 float widthmax = node->typeinfo->maxwidth;
989
990 {
991 if (nsw->directions & NODE_RESIZE_RIGHT) {
992 *pwidth = oldwidth + dx;
993 CLAMP(*pwidth, widthmin, widthmax);
994 }
995 if (nsw->directions & NODE_RESIZE_LEFT) {
996 float locmax = nsw->oldlocx + oldwidth;
997
998 node->locx = nsw->oldlocx + dx;
999 CLAMP(node->locx, locmax - widthmax, locmax - widthmin);
1000 *pwidth = locmax - node->locx;
1001 }
1002 }
1003
1004 /* Height works the other way round. */
1005 {
1006 float heightmin = UI_SCALE_FAC * node->typeinfo->minheight;
1007 float heightmax = UI_SCALE_FAC * node->typeinfo->maxheight;
1008 if (nsw->directions & NODE_RESIZE_TOP) {
1009 float locmin = nsw->oldlocy - nsw->oldheight;
1010
1011 node->locy = nsw->oldlocy + dy;
1012 CLAMP(node->locy, locmin + heightmin, locmin + heightmax);
1013 node->height = node->locy - locmin;
1014 }
1015 if (nsw->directions & NODE_RESIZE_BOTTOM) {
1016 node->height = nsw->oldheight - dy;
1017 CLAMP(node->height, heightmin, heightmax);
1018 }
1019 }
1020
1021 if (node->type == NODE_FRAME) {
1022 /* Keep the offset symmetric around center point. */
1023 if (nsw->directions & NODE_RESIZE_LEFT) {
1024 node->locx = nsw->oldlocx + 0.5f * dx;
1025 node->offsetx = nsw->oldoffsetx + 0.5f * dx;
1026 }
1027 if (nsw->directions & NODE_RESIZE_RIGHT) {
1028 node->locx = nsw->oldlocx + 0.5f * dx;
1029 node->offsetx = nsw->oldoffsetx - 0.5f * dx;
1030 }
1031 if (nsw->directions & NODE_RESIZE_TOP) {
1032 node->locy = nsw->oldlocy + 0.5f * dy;
1033 node->offsety = nsw->oldoffsety + 0.5f * dy;
1034 }
1035 if (nsw->directions & NODE_RESIZE_BOTTOM) {
1036 node->locy = nsw->oldlocy + 0.5f * dy;
1037 node->offsety = nsw->oldoffsety - 0.5f * dy;
1038 }
1039 }
1040 }
1041
1042 ED_region_tag_redraw(region);
1043
1044 break;
1045 }
1046 case LEFTMOUSE:
1047 case MIDDLEMOUSE:
1048 case RIGHTMOUSE: {
1049 if (event->val == KM_RELEASE) {
1050 node_resize_exit(C, op, false);
1052
1053 return OPERATOR_FINISHED;
1054 }
1055 if (event->val == KM_PRESS) {
1056 node_resize_exit(C, op, true);
1057 ED_region_tag_redraw(region);
1058
1059 return OPERATOR_CANCELLED;
1060 }
1061 break;
1062 }
1063 case EVT_ESCKEY:
1064 node_resize_exit(C, op, true);
1065 ED_region_tag_redraw(region);
1066 return OPERATOR_CANCELLED;
1067 }
1068
1070}
1071
1072static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1073{
1074 SpaceNode *snode = CTX_wm_space_node(C);
1075 ARegion *region = CTX_wm_region(C);
1076 const bNode *node = bke::node_get_active(snode->edittree);
1077
1078 if (node == nullptr) {
1080 }
1081
1082 /* Convert mouse coordinates to `v2d` space. */
1083 float2 cursor;
1084 int2 mval;
1085 WM_event_drag_start_mval(event, region, mval);
1086 UI_view2d_region_to_view(&region->v2d, mval.x, mval.y, &cursor.x, &cursor.y);
1087 const NodeResizeDirection dir = node_get_resize_direction(*snode, node, cursor.x, cursor.y);
1088 if (dir == NODE_RESIZE_NONE) {
1090 }
1091
1092 node_resize_init(C, op, cursor, node, dir);
1094}
1095
1097{
1098 node_resize_exit(C, op, true);
1099}
1100
1102{
1103 /* identifiers */
1104 ot->name = "Resize Node";
1105 ot->idname = "NODE_OT_resize";
1106 ot->description = "Resize a node";
1107
1108 /* api callbacks */
1113
1114 /* flags */
1116}
1117
1120/* -------------------------------------------------------------------- */
1125{
1126 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1127 if (sock->flag & SOCK_HIDDEN) {
1128 return true;
1129 }
1130 }
1131 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
1132 if (sock->flag & SOCK_HIDDEN) {
1133 return true;
1134 }
1135 }
1136 return false;
1137}
1138
1139void node_set_hidden_sockets(bNode *node, int set)
1140{
1141 /* The Reroute node is the socket itself, do not hide this. */
1142 if (node->is_reroute()) {
1143 return;
1144 }
1145
1146 if (set == 0) {
1147 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1148 sock->flag &= ~SOCK_HIDDEN;
1149 }
1150 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
1151 sock->flag &= ~SOCK_HIDDEN;
1152 }
1153 }
1154 else {
1155 /* Hide unused sockets. */
1156 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1157 if (sock->link == nullptr) {
1158 sock->flag |= SOCK_HIDDEN;
1159 }
1160 }
1161 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
1162 if ((sock->flag & SOCK_IS_LINKED) == 0) {
1163 sock->flag |= SOCK_HIDDEN;
1164 }
1165 }
1166 }
1167}
1168
1169bool node_is_previewable(const SpaceNode &snode, const bNodeTree &ntree, const bNode &node)
1170{
1171 if (!(snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS) ||
1173 {
1174 return false;
1175 }
1176 if (ntree.type == NTREE_SHADER) {
1177 return U.experimental.use_shader_node_previews && !node.is_frame();
1178 }
1179 return node.typeinfo->flag & NODE_PREVIEW;
1180}
1181
1182static bool cursor_isect_multi_input_socket(const float2 &cursor, const bNodeSocket &socket)
1183{
1184 const float node_socket_height = node_socket_calculate_height(socket);
1185 const float2 location = socket.runtime->location;
1186 /* `.xmax = socket->locx + NODE_SOCKSIZE * 5.5f`
1187 * would be the same behavior as for regular sockets.
1188 * But keep it smaller because for multi-input socket you
1189 * sometimes want to drag the link to the other side, if you may
1190 * accidentally pick the wrong link otherwise. */
1191 rctf multi_socket_rect;
1192 BLI_rctf_init(&multi_socket_rect,
1193 location.x - NODE_SOCKSIZE * 4.0f,
1194 location.x + NODE_SOCKSIZE * 2.0f,
1195 location.y - node_socket_height,
1196 location.y + node_socket_height);
1197 if (BLI_rctf_isect_pt(&multi_socket_rect, cursor.x, cursor.y)) {
1198 return true;
1199 }
1200 return false;
1201}
1202
1204 ARegion &region,
1205 const float2 &cursor,
1206 const eNodeSocketInOut in_out)
1207{
1208 const float view2d_scale = UI_view2d_scale_get_x(&region.v2d);
1209 const float max_distance = NODE_SOCKSIZE + std::clamp(20.0f / view2d_scale, 5.0f, 30.0f);
1210 const float padded_socket_size = NODE_SOCKSIZE + 4;
1211
1212 bNodeTree &tree = *snode.edittree;
1213 tree.ensure_topology_cache();
1214
1216 if (sorted_nodes.is_empty()) {
1217 return nullptr;
1218 }
1219
1220 float best_distance = FLT_MAX;
1221 bNodeSocket *best_socket = nullptr;
1222
1223 auto update_best_socket = [&](bNodeSocket *socket, const float distance) {
1224 if (socket_is_occluded(socket->runtime->location, socket->owner_node(), sorted_nodes)) {
1225 return;
1226 }
1227 if (distance < best_distance) {
1228 best_distance = distance;
1229 best_socket = socket;
1230 }
1231 };
1232
1233 for (bNode *node : sorted_nodes) {
1234 const bool node_hidden = node->flag & NODE_HIDDEN;
1235 if (!node->is_reroute() && !node_hidden && node->runtime->totr.ymax - cursor.y < NODE_DY) {
1236 /* Don't pick socket when cursor is over node header. This allows the user to always resize
1237 * by dragging on the left and right side of the header. */
1238 continue;
1239 }
1240 if (in_out & SOCK_IN) {
1241 for (bNodeSocket *sock : node->input_sockets()) {
1242 if (!node->is_socket_icon_drawn(*sock)) {
1243 continue;
1244 }
1245 const float2 location = sock->runtime->location;
1246 const float distance = math::distance(location, cursor);
1247 if (sock->flag & SOCK_MULTI_INPUT && !node_hidden) {
1248 if (cursor_isect_multi_input_socket(cursor, *sock)) {
1249 update_best_socket(sock, distance);
1250 continue;
1251 }
1252 }
1253 if (distance < max_distance) {
1254 update_best_socket(sock, distance);
1255 }
1256 }
1257 }
1258 if (in_out & SOCK_OUT) {
1259 for (bNodeSocket *sock : node->output_sockets()) {
1260 if (!node->is_socket_icon_drawn(*sock)) {
1261 continue;
1262 }
1263 const float2 location = sock->runtime->location;
1264 const float distance = math::distance(location, cursor);
1265 if (distance < max_distance) {
1266 if (node_hidden) {
1267 if (location.x - cursor.x > padded_socket_size) {
1268 /* Needed to be able to resize collapsed nodes. */
1269 continue;
1270 }
1271 }
1272 update_best_socket(sock, distance);
1273 }
1274 }
1275 }
1276 }
1277
1278 return best_socket;
1279}
1280
1283/* -------------------------------------------------------------------- */
1287float node_link_dim_factor(const View2D &v2d, const bNodeLink &link)
1288{
1289 if (link.fromsock == nullptr || link.tosock == nullptr) {
1290 return 1.0f;
1291 }
1293 return 0.2f;
1294 }
1295
1296 const float2 from = link.fromsock->runtime->location;
1297 const float2 to = link.tosock->runtime->location;
1298
1299 const float min_endpoint_distance = std::min(
1300 std::max(BLI_rctf_length_x(&v2d.cur, from.x), BLI_rctf_length_y(&v2d.cur, from.y)),
1301 std::max(BLI_rctf_length_x(&v2d.cur, to.x), BLI_rctf_length_y(&v2d.cur, to.y)));
1302
1303 if (min_endpoint_distance == 0.0f) {
1304 return 1.0f;
1305 }
1306 const float viewport_width = BLI_rctf_size_x(&v2d.cur);
1307 return std::clamp(1.0f - min_endpoint_distance / viewport_width * 10.0f, 0.05f, 1.0f);
1308}
1309
1311{
1312 return bke::node_link_is_hidden(&link) || node_link_dim_factor(v2d, link) < 0.5f;
1313}
1314
1317/* -------------------------------------------------------------------- */
1322 const Map<bNode *, bNode *> &node_map,
1323 bNode *node)
1324{
1325 bNode *parent;
1326
1327 node->flag |= NODE_TEST;
1328
1329 /* Find first selected parent. */
1330 for (parent = node->parent; parent; parent = parent->parent) {
1331 if (parent->flag & SELECT) {
1332 if (!(parent->flag & NODE_TEST)) {
1333 node_duplicate_reparent_recursive(ntree, node_map, parent);
1334 }
1335 break;
1336 }
1337 }
1338 /* Reparent node copy to parent copy. */
1339 if (parent) {
1340 bke::node_detach_node(ntree, node_map.lookup(node));
1341 bke::node_attach_node(ntree, node_map.lookup(node), node_map.lookup(parent));
1342 }
1343}
1344
1346{
1347 /* We don't have the old tree for looking up output nodes by ID,
1348 * so we have to build a map first to find copied output nodes in the new tree. */
1349 Map<int32_t, bNode *> dst_output_node_map;
1350 for (const auto &item : node_map.items()) {
1351 if (bke::all_zone_output_node_types().contains(item.key->type)) {
1352 dst_output_node_map.add_new(item.key->identifier, item.value);
1353 }
1354 }
1355
1356 for (bNode *dst_node : node_map.values()) {
1357 if (bke::all_zone_input_node_types().contains(dst_node->type)) {
1358 const bke::bNodeZoneType &zone_type = *bke::zone_type_by_node_type(dst_node->type);
1359 int &output_node_id = zone_type.get_corresponding_output_id(*dst_node);
1360 if (const bNode *output_node = dst_output_node_map.lookup_default(output_node_id, nullptr)) {
1361 output_node_id = output_node->identifier;
1362 }
1363 else {
1364 output_node_id = 0;
1366 }
1367 }
1368 }
1369}
1370
1372{
1373 Main *bmain = CTX_data_main(C);
1374 SpaceNode *snode = CTX_wm_space_node(C);
1375 bNodeTree *ntree = snode->edittree;
1376 const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
1377 bool linked = RNA_boolean_get(op->ptr, "linked") || ((U.dupflag & USER_DUP_NTREE) == 0);
1378 const bool dupli_node_tree = !linked;
1379
1381
1382 Map<bNode *, bNode *> node_map;
1384 Map<const ID *, ID *> duplicated_node_groups;
1385
1386 node_select_paired(*ntree);
1387
1388 for (bNode *node : get_selected_nodes(*ntree)) {
1390 ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
1391 node_map.add_new(node, new_node);
1392
1393 if (node->id && dupli_node_tree) {
1394 ID *new_group = duplicated_node_groups.lookup_or_add_cb(node->id, [&]() {
1395 ID *new_group = BKE_id_copy(bmain, node->id);
1396 /* Remove user added by copying. */
1397 id_us_min(new_group);
1398 return new_group;
1399 });
1400 id_us_plus(new_group);
1401 id_us_min(new_node->id);
1402 new_node->id = new_group;
1403 }
1404 }
1405
1406 if (node_map.is_empty()) {
1407 return OPERATOR_CANCELLED;
1408 }
1409
1410 /* Copy links between selected nodes. */
1411 bNodeLink *lastlink = (bNodeLink *)ntree->links.last;
1412 LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
1413 /* This creates new links between copied nodes. If keep_inputs is set, also copies input links
1414 * from unselected (when fromnode is null)! */
1415 if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
1416 (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT))))
1417 {
1418 bNodeLink *newlink = MEM_cnew<bNodeLink>("bNodeLink");
1419 newlink->flag = link->flag;
1420 newlink->tonode = node_map.lookup(link->tonode);
1421 newlink->tosock = socket_map.lookup(link->tosock);
1422
1423 if (link->tosock->flag & SOCK_MULTI_INPUT) {
1424 newlink->multi_input_sort_id = link->multi_input_sort_id;
1425 }
1426
1427 if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
1428 newlink->fromnode = node_map.lookup(link->fromnode);
1429 newlink->fromsock = socket_map.lookup(link->fromsock);
1430 }
1431 else {
1432 /* Input node not copied, this keeps the original input linked. */
1433 newlink->fromnode = link->fromnode;
1434 newlink->fromsock = link->fromsock;
1435 }
1436
1437 BLI_addtail(&ntree->links, newlink);
1438 }
1439
1440 /* Make sure we don't copy new links again. */
1441 if (link == lastlink) {
1442 break;
1443 }
1444 }
1445
1446 for (bNode *node : node_map.values()) {
1448 }
1449
1450 ntree->ensure_topology_cache();
1451 for (bNode *node : node_map.values()) {
1453 }
1454
1455 /* Clear flags for recursive depth-first iteration. */
1456 for (bNode *node : ntree->all_nodes()) {
1457 node->flag &= ~NODE_TEST;
1458 }
1459 /* Reparent copied nodes. */
1460 for (bNode *node : node_map.keys()) {
1461 if (!(node->flag & NODE_TEST)) {
1462 node_duplicate_reparent_recursive(ntree, node_map, node);
1463 }
1464 }
1465
1466 {
1467 /* Use temporary map that has const key, because that's what the function below expects. */
1468 Map<const bNode *, bNode *> const_node_map;
1469 for (const auto item : node_map.items()) {
1470 const_node_map.add(item.key, item.value);
1471 }
1472 remap_node_pairing(*ntree, const_node_map);
1473 }
1474
1475 /* Deselect old nodes, select the copies instead. */
1476 for (const auto item : node_map.items()) {
1477 bNode *src_node = item.key;
1478 bNode *dst_node = item.value;
1479
1480 bke::node_set_selected(src_node, false);
1481 src_node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
1482 bke::node_set_selected(dst_node, true);
1483 }
1484
1486 ED_node_tree_propagate_change(C, bmain, snode->edittree);
1487 return OPERATOR_FINISHED;
1488}
1489
1491{
1492 PropertyRNA *prop;
1493
1494 /* identifiers */
1495 ot->name = "Duplicate Nodes";
1496 ot->description = "Duplicate selected nodes";
1497 ot->idname = "NODE_OT_duplicate";
1498
1499 /* api callbacks */
1502
1503 /* flags */
1505
1507 ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes");
1508
1509 prop = RNA_def_boolean(ot->srna,
1510 "linked",
1511 true,
1512 "Linked",
1513 "Duplicate node but not node trees, linking to the original data");
1515}
1516
1517/* Goes over all scenes, reads render layers. */
1519{
1520 Main *bmain = CTX_data_main(C);
1521 SpaceNode *snode = CTX_wm_space_node(C);
1522 Scene *curscene = CTX_data_scene(C);
1523 bNodeTree &edit_tree = *snode->edittree;
1524
1526
1527 /* first tag scenes unread */
1528 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1529 scene->id.tag |= ID_TAG_DOIT;
1530 }
1531
1532 for (bNode *node : edit_tree.all_nodes()) {
1533 if ((node->type == CMP_NODE_R_LAYERS) || (node->type == CMP_NODE_CRYPTOMATTE &&
1534 node->custom1 == CMP_NODE_CRYPTOMATTE_SOURCE_RENDER))
1535 {
1536 ID *id = node->id;
1537 if (id == nullptr) {
1538 continue;
1539 }
1540 if (id->tag & ID_TAG_DOIT) {
1541 RE_ReadRenderResult(curscene, (Scene *)id);
1543 id->tag &= ~ID_TAG_DOIT;
1544 }
1545 }
1546 }
1547
1548 ED_node_tree_propagate_change(C, bmain, &edit_tree);
1549
1550 return OPERATOR_FINISHED;
1551}
1552
1554{
1555 ot->name = "Read View Layers";
1556 ot->idname = "NODE_OT_read_viewlayers";
1557 ot->description = "Read all render layers of all used scenes";
1558
1560
1562}
1563
1565{
1566 Scene *sce = CTX_data_scene(C);
1567
1568 /* This is actually a test whether scene is used by the compositor or not.
1569 * All the nodes are using same render result, so there is no need to do
1570 * anything smart about check how exactly scene is used. */
1571 bNode *node = nullptr;
1572 for (bNode *node_iter : sce->nodetree->all_nodes()) {
1573 if (node_iter->id == (ID *)sce) {
1574 node = node_iter;
1575 break;
1576 }
1577 }
1578
1579 if (node) {
1580 ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&sce->view_layers, node->custom1);
1581
1582 if (view_layer) {
1583 PointerRNA op_ptr;
1584
1585 WM_operator_properties_create(&op_ptr, "RENDER_OT_render");
1586 RNA_string_set(&op_ptr, "layer", view_layer->name);
1587 RNA_string_set(&op_ptr, "scene", sce->id.name + 2);
1588
1589 /* To keep keyframe positions. */
1590 sce->r.scemode |= R_NO_FRAME_UPDATE;
1591
1592 WM_operator_name_call(C, "RENDER_OT_render", WM_OP_INVOKE_DEFAULT, &op_ptr, nullptr);
1593
1595
1596 return OPERATOR_FINISHED;
1597 }
1598 }
1599 return OPERATOR_CANCELLED;
1600}
1601
1603{
1604 ot->name = "Render Changed Layer";
1605 ot->idname = "NODE_OT_render_changed";
1606 ot->description = "Render current scene, when input node's layer has been changed";
1607
1609
1611
1612 /* flags */
1613 ot->flag = 0;
1614}
1615
1618/* -------------------------------------------------------------------- */
1626static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag)
1627{
1628 int tot_eq = 0, tot_neq = 0;
1629
1630 for (bNode *node : snode->edittree->all_nodes()) {
1631 if (node->flag & SELECT) {
1632
1633 if (toggle_flag == NODE_PREVIEW && !node_is_previewable(*snode, *snode->edittree, *node)) {
1634 continue;
1635 }
1636 if (toggle_flag == NODE_OPTIONS &&
1637 !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
1638 {
1639 continue;
1640 }
1641
1642 if (node->flag & toggle_flag) {
1643 tot_eq++;
1644 }
1645 else {
1646 tot_neq++;
1647 }
1648 }
1649 }
1650 for (bNode *node : snode->edittree->all_nodes()) {
1651 if (node->flag & SELECT) {
1652
1653 if (toggle_flag == NODE_PREVIEW && !node_is_previewable(*snode, *snode->edittree, *node)) {
1654 continue;
1655 }
1656 if (toggle_flag == NODE_OPTIONS &&
1657 !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
1658 {
1659 continue;
1660 }
1661
1662 if ((tot_eq && tot_neq) || tot_eq == 0) {
1663 node->flag |= toggle_flag;
1664 }
1665 else {
1666 node->flag &= ~toggle_flag;
1667 }
1668 }
1669 }
1670}
1671
1673{
1674 SpaceNode *snode = CTX_wm_space_node(C);
1675
1676 /* Sanity checking (poll callback checks this already). */
1677 if ((snode == nullptr) || (snode->edittree == nullptr)) {
1678 return OPERATOR_CANCELLED;
1679 }
1680
1682
1684
1685 return OPERATOR_FINISHED;
1686}
1687
1689{
1690 /* identifiers */
1691 ot->name = "Hide";
1692 ot->description = "Toggle hiding of selected nodes";
1693 ot->idname = "NODE_OT_hide_toggle";
1694
1695 /* callbacks */
1698
1699 /* flags */
1701}
1702
1704{
1705 SpaceNode *snode = CTX_wm_space_node(C);
1706
1707 /* Sanity checking (poll callback checks this already). */
1708 if ((snode == nullptr) || (snode->edittree == nullptr)) {
1709 return OPERATOR_CANCELLED;
1710 }
1711
1713
1715
1716 return OPERATOR_FINISHED;
1717}
1718
1720{
1721 if (ED_operator_node_active(C)) {
1722 SpaceNode *snode = CTX_wm_space_node(C);
1723 if (ED_node_supports_preview(snode)) {
1724 return true;
1725 }
1726 }
1727 return false;
1728}
1729
1731{
1732 /* identifiers */
1733 ot->name = "Toggle Node Preview";
1734 ot->description = "Toggle preview display for selected nodes";
1735 ot->idname = "NODE_OT_preview_toggle";
1736
1737 /* callbacks */
1740
1741 /* flags */
1743}
1744
1746{
1747 SpaceNode &snode = *CTX_wm_space_node(C);
1748 WorkSpace &workspace = *CTX_wm_workspace(C);
1749
1750 bNode *active_viewer = viewer_path::find_geometry_nodes_viewer(workspace.viewer_path, snode);
1751
1752 for (bNode *node : snode.edittree->all_nodes()) {
1753 if (node->type != GEO_NODE_VIEWER) {
1754 continue;
1755 }
1756 if (!(node->flag & SELECT)) {
1757 continue;
1758 }
1759 if (node == active_viewer) {
1760 node->flag &= ~NODE_DO_OUTPUT;
1762 }
1763 }
1764
1766
1767 return OPERATOR_FINISHED;
1768}
1769
1771{
1772 /* identifiers */
1773 ot->name = "Deactivate Viewer Node";
1774 ot->description = "Deactivate selected viewer node in geometry nodes";
1775 ot->idname = __func__;
1776
1777 /* callbacks */
1780
1781 /* flags */
1783}
1784
1786{
1787 SpaceNode *snode = CTX_wm_space_node(C);
1788
1789 /* Sanity checking (poll callback checks this already). */
1790 if ((snode == nullptr) || (snode->edittree == nullptr)) {
1791 return OPERATOR_CANCELLED;
1792 }
1793
1795
1797
1798 return OPERATOR_FINISHED;
1799}
1800
1802{
1803 /* identifiers */
1804 ot->name = "Toggle Node Options";
1805 ot->description = "Toggle option buttons display for selected nodes";
1806 ot->idname = "NODE_OT_options_toggle";
1807
1808 /* callbacks */
1811
1812 /* flags */
1814}
1815
1817{
1818 SpaceNode *snode = CTX_wm_space_node(C);
1819
1820 /* Sanity checking (poll callback checks this already). */
1821 if ((snode == nullptr) || (snode->edittree == nullptr)) {
1822 return OPERATOR_CANCELLED;
1823 }
1824
1826
1827 /* Toggle for all selected nodes */
1828 bool hidden = false;
1829 for (bNode *node : snode->edittree->all_nodes()) {
1830 if (node->flag & SELECT) {
1831 if (node_has_hidden_sockets(node)) {
1832 hidden = true;
1833 break;
1834 }
1835 }
1836 }
1837
1838 for (bNode *node : snode->edittree->all_nodes()) {
1839 if (node->flag & SELECT) {
1840 node_set_hidden_sockets(node, !hidden);
1841 }
1842 }
1843
1845
1847 /* Hack to force update of the button state after drawing, see #112462. */
1849
1850 return OPERATOR_FINISHED;
1851}
1852
1854{
1855 /* identifiers */
1856 ot->name = "Toggle Hidden Node Sockets";
1857 ot->description = "Toggle unused node socket display";
1858 ot->idname = "NODE_OT_hide_socket_toggle";
1859
1860 /* callbacks */
1863
1864 /* flags */
1866}
1867
1870/* -------------------------------------------------------------------- */
1874static int node_mute_exec(bContext *C, wmOperator * /*op*/)
1875{
1876 Main *bmain = CTX_data_main(C);
1877 SpaceNode *snode = CTX_wm_space_node(C);
1878
1880
1881 for (bNode *node : snode->edittree->all_nodes()) {
1882 if ((node->flag & SELECT) && !node->typeinfo->no_muting) {
1883 node->flag ^= NODE_MUTED;
1885 }
1886 }
1887
1888 ED_node_tree_propagate_change(C, bmain, snode->edittree);
1889
1890 return OPERATOR_FINISHED;
1891}
1892
1894{
1895 /* identifiers */
1896 ot->name = "Toggle Node Mute";
1897 ot->description = "Toggle muting of selected nodes";
1898 ot->idname = "NODE_OT_mute_toggle";
1899
1900 /* callbacks */
1903
1904 /* flags */
1906}
1907
1910/* -------------------------------------------------------------------- */
1914static int node_delete_exec(bContext *C, wmOperator * /*op*/)
1915{
1916 Main *bmain = CTX_data_main(C);
1917 SpaceNode *snode = CTX_wm_space_node(C);
1918
1920
1921 /* Delete paired nodes as well. */
1923
1924 LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
1925 if (node->flag & SELECT) {
1926 bke::node_remove_node(bmain, snode->edittree, node, true);
1927 }
1928 }
1929
1930 ED_node_tree_propagate_change(C, bmain, snode->edittree);
1931
1932 return OPERATOR_FINISHED;
1933}
1934
1936{
1937 /* identifiers */
1938 ot->name = "Delete";
1939 ot->description = "Remove selected nodes";
1940 ot->idname = "NODE_OT_delete";
1941
1942 /* api callbacks */
1945
1946 /* flags */
1948}
1949
1952/* -------------------------------------------------------------------- */
1957{
1958 Main *bmain = CTX_data_main(C);
1959 SpaceNode *snode = CTX_wm_space_node(C);
1960
1962
1963 /* Delete paired nodes as well. */
1965
1966 LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
1967 if (node->flag & SELECT) {
1969 bke::node_remove_node(bmain, snode->edittree, node, true);
1970
1971 /* Since this node might have been animated, and that animation data been
1972 * deleted, a notifier call is necessary to redraw any animation editor. */
1974 }
1975 }
1976
1977 ED_node_tree_propagate_change(C, bmain, snode->edittree);
1978
1979 return OPERATOR_FINISHED;
1980}
1981
1983{
1984 /* identifiers */
1985 ot->name = "Delete with Reconnect";
1986 ot->description = "Remove nodes and reconnect nodes as if deletion was muted";
1987 ot->idname = "NODE_OT_delete_reconnect";
1988
1989 /* api callbacks */
1992
1993 /* flags */
1995}
1996
1999/* -------------------------------------------------------------------- */
2004{
2005 Scene *scene = CTX_data_scene(C);
2006 SpaceNode *snode = CTX_wm_space_node(C);
2007 PointerRNA ptr = CTX_data_pointer_get(C, "node");
2008 bNodeTree *ntree = nullptr;
2009 bNode *node = nullptr;
2010 char file_path[MAX_NAME];
2011
2012 if (ptr.data) {
2013 node = (bNode *)ptr.data;
2014 ntree = (bNodeTree *)ptr.owner_id;
2015 }
2016 else if (snode && snode->edittree) {
2017 ntree = snode->edittree;
2018 node = bke::node_get_active(snode->edittree);
2019 }
2020
2021 if (!node || node->type != CMP_NODE_OUTPUT_FILE) {
2022 return OPERATOR_CANCELLED;
2023 }
2024
2025 RNA_string_get(op->ptr, "file_path", file_path);
2026 ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
2027
2029
2030 return OPERATOR_FINISHED;
2031}
2032
2034{
2035 /* identifiers */
2036 ot->name = "Add File Node Socket";
2037 ot->description = "Add a new input to a file output node";
2038 ot->idname = "NODE_OT_output_file_add_socket";
2039
2040 /* callbacks */
2043
2044 /* flags */
2046
2048 ot->srna, "file_path", "Image", MAX_NAME, "File Path", "Subpath of the output file");
2049}
2050
2053/* -------------------------------------------------------------------- */
2058{
2059 SpaceNode *snode = CTX_wm_space_node(C);
2060 PointerRNA ptr = CTX_data_pointer_get(C, "node");
2061 bNodeTree *ntree = nullptr;
2062 bNode *node = nullptr;
2063
2064 if (ptr.data) {
2065 node = (bNode *)ptr.data;
2066 ntree = (bNodeTree *)ptr.owner_id;
2067 }
2068 else if (snode && snode->edittree) {
2069 ntree = snode->edittree;
2070 node = bke::node_get_active(snode->edittree);
2071 }
2072
2073 if (!node || node->type != CMP_NODE_OUTPUT_FILE) {
2074 return OPERATOR_CANCELLED;
2075 }
2076
2078 return OPERATOR_CANCELLED;
2079 }
2080
2082
2083 return OPERATOR_FINISHED;
2084}
2085
2087{
2088 /* identifiers */
2089 ot->name = "Remove File Node Socket";
2090 ot->description = "Remove the active input from a file output node";
2091 ot->idname = "NODE_OT_output_file_remove_active_socket";
2092
2093 /* callbacks */
2096
2097 /* flags */
2099}
2100
2103/* -------------------------------------------------------------------- */
2108{
2109 SpaceNode *snode = CTX_wm_space_node(C);
2110 PointerRNA ptr = CTX_data_pointer_get(C, "node");
2111 bNode *node = nullptr;
2112
2113 if (ptr.data) {
2114 node = (bNode *)ptr.data;
2115 }
2116 else if (snode && snode->edittree) {
2117 node = bke::node_get_active(snode->edittree);
2118 }
2119
2120 if (!node || node->type != CMP_NODE_OUTPUT_FILE) {
2121 return OPERATOR_CANCELLED;
2122 }
2123
2124 NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
2125
2126 bNodeSocket *sock = (bNodeSocket *)BLI_findlink(&node->inputs, nimf->active_input);
2127 if (!sock) {
2128 return OPERATOR_CANCELLED;
2129 }
2130
2131 int direction = RNA_enum_get(op->ptr, "direction");
2132
2133 if (direction == 1) {
2134 bNodeSocket *before = sock->prev;
2135 if (!before) {
2136 return OPERATOR_CANCELLED;
2137 }
2138 BLI_remlink(&node->inputs, sock);
2139 BLI_insertlinkbefore(&node->inputs, before, sock);
2140 nimf->active_input--;
2141 }
2142 else {
2143 bNodeSocket *after = sock->next;
2144 if (!after) {
2145 return OPERATOR_CANCELLED;
2146 }
2147 BLI_remlink(&node->inputs, sock);
2148 BLI_insertlinkafter(&node->inputs, after, sock);
2149 nimf->active_input++;
2150 }
2151
2154
2155 return OPERATOR_FINISHED;
2156}
2157
2159{
2160 static const EnumPropertyItem direction_items[] = {
2161 {1, "UP", 0, "Up", ""}, {2, "DOWN", 0, "Down", ""}, {0, nullptr, 0, nullptr, nullptr}};
2162
2163 /* identifiers */
2164 ot->name = "Move File Node Socket";
2165 ot->description = "Move the active input of a file output node up or down the list";
2166 ot->idname = "NODE_OT_output_file_move_active_socket";
2167
2168 /* callbacks */
2171
2172 /* flags */
2174
2175 RNA_def_enum(ot->srna, "direction", direction_items, 2, "Direction", "");
2176}
2177
2180/* -------------------------------------------------------------------- */
2185{
2186 SpaceNode &snode = *CTX_wm_space_node(C);
2187 bNodeTree &ntree = *snode.edittree;
2188
2189 bNode *active_node = bke::node_get_active(&ntree);
2190 if (!active_node) {
2191 return OPERATOR_CANCELLED;
2192 }
2193
2194 for (bNode *node : ntree.all_nodes()) {
2195 if (node->flag & NODE_SELECT && node != active_node) {
2196 if (active_node->flag & NODE_CUSTOM_COLOR) {
2197 node->flag |= NODE_CUSTOM_COLOR;
2198 copy_v3_v3(node->color, active_node->color);
2199 }
2200 else {
2201 node->flag &= ~NODE_CUSTOM_COLOR;
2202 }
2203 }
2204 }
2205
2207
2208 return OPERATOR_FINISHED;
2209}
2210
2212{
2213 /* identifiers */
2214 ot->name = "Copy Color";
2215 ot->description = "Copy color to all selected nodes";
2216 ot->idname = "NODE_OT_node_copy_color";
2217
2218 /* api callbacks */
2221
2222 /* flags */
2224}
2225
2228/* -------------------------------------------------------------------- */
2233{
2234 Scene *scene = CTX_data_scene(C);
2235 const RenderEngineType *type = RE_engines_find(scene->r.engine);
2236 SpaceNode *snode = CTX_wm_space_node(C);
2237
2238 /* Test if we have a render engine that supports shaders scripts. */
2239 if (!(type && type->update_script_node)) {
2240 return false;
2241 }
2242
2243 /* See if we have a shader script node in context. */
2244 bNode *node = (bNode *)CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data;
2245
2246 if (!node && snode && snode->edittree) {
2247 node = bke::node_get_active(snode->edittree);
2248 }
2249
2250 if (node && node->type == SH_NODE_SCRIPT) {
2251 NodeShaderScript *nss = (NodeShaderScript *)node->storage;
2252
2253 if (node->id || nss->filepath[0]) {
2254 return ED_operator_node_editable(C);
2255 }
2256 }
2257
2258 /* See if we have a text datablock in context. */
2259 Text *text = (Text *)CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data;
2260 if (text) {
2261 return true;
2262 }
2263
2264 /* We don't check if text datablock is actually in use, too slow for poll. */
2265
2266 return false;
2267}
2268
2269/* recursively check for script nodes in groups using this text and update */
2271 RenderEngineType *type,
2272 bNodeTree *ntree,
2273 Text *text,
2274 VectorSet<bNodeTree *> &done_trees)
2275{
2276 bool found = false;
2277
2278 done_trees.add_new(ntree);
2279
2280 /* Update each script that is using this text datablock. */
2281 for (bNode *node : ntree->all_nodes()) {
2282 if (node->type == NODE_GROUP) {
2283 bNodeTree *ngroup = (bNodeTree *)node->id;
2284 if (ngroup && !done_trees.contains(ngroup)) {
2285 found |= node_shader_script_update_text_recursive(engine, type, ngroup, text, done_trees);
2286 }
2287 }
2288 else if (node->type == SH_NODE_SCRIPT && node->id == &text->id) {
2289 type->update_script_node(engine, ntree, node);
2290 found = true;
2291 }
2292 }
2293
2294 return found;
2295}
2296
2298{
2299 Main *bmain = CTX_data_main(C);
2300 Scene *scene = CTX_data_scene(C);
2301 SpaceNode *snode = CTX_wm_space_node(C);
2302 PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript);
2303 bool found = false;
2304
2305 /* setup render engine */
2306 RenderEngineType *type = RE_engines_find(scene->r.engine);
2307 RenderEngine *engine = RE_engine_create(type);
2308 engine->reports = op->reports;
2309
2310 bNodeTree *ntree_base = nullptr;
2311 bNode *node = nullptr;
2312 if (nodeptr.data) {
2313 ntree_base = (bNodeTree *)nodeptr.owner_id;
2314 node = (bNode *)nodeptr.data;
2315 }
2316 else if (snode && snode->edittree) {
2317 ntree_base = snode->edittree;
2318 node = bke::node_get_active(snode->edittree);
2319 }
2320
2321 if (node) {
2322 /* Update single node. */
2323 type->update_script_node(engine, ntree_base, node);
2324
2325 found = true;
2326 }
2327 else {
2328 /* Update all nodes using text datablock. */
2329 Text *text = (Text *)CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data;
2330
2331 if (text) {
2332
2333 VectorSet<bNodeTree *> done_trees;
2334
2335 FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
2336 if (ntree->type == NTREE_SHADER) {
2337 if (!done_trees.contains(ntree)) {
2339 engine, type, ntree, text, done_trees);
2340 }
2341 }
2342 }
2344
2345 if (!found) {
2346 BKE_report(op->reports, RPT_INFO, "Text not used by any node, no update done");
2347 }
2348 }
2349 }
2350
2351 RE_engine_free(engine);
2352
2353 return (found) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2354}
2355
2357{
2358 /* identifiers */
2359 ot->name = "Script Node Update";
2360 ot->description = "Update shader script node with new sockets and options from the script";
2361 ot->idname = "NODE_OT_shader_script_update";
2362
2363 /* api callbacks */
2366
2367 /* flags */
2369}
2370
2373/* -------------------------------------------------------------------- */
2378 ARegion *region,
2379 int x,
2380 int y,
2381 int backdrop_width,
2382 int backdrop_height,
2383 float *fx,
2384 float *fy)
2385{
2386 float bufx = backdrop_width * snode->zoom;
2387 float bufy = backdrop_height * snode->zoom;
2388
2389 *fx = (bufx > 0.0f ? (float(x) - 0.5f * region->winx - snode->xof) / bufx + 0.5f : 0.0f);
2390 *fy = (bufy > 0.0f ? (float(y) - 0.5f * region->winy - snode->yof) / bufy + 0.5f : 0.0f);
2391}
2392
2394{
2395 Main *bmain = CTX_data_main(C);
2396 void *lock;
2397
2399
2400 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
2401 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
2402
2403 if (ibuf) {
2404 ARegion *region = CTX_wm_region(C);
2405 SpaceNode *snode = CTX_wm_space_node(C);
2406 bNodeTree *btree = snode->nodetree;
2407 rcti rect;
2408 rctf rectf;
2409
2410 /* Get border from operator. */
2412
2413 /* Convert border to unified space within backdrop image. */
2415 snode, region, rect.xmin, rect.ymin, ibuf->x, ibuf->y, &rectf.xmin, &rectf.ymin);
2416
2418 snode, region, rect.xmax, rect.ymax, ibuf->x, ibuf->y, &rectf.xmax, &rectf.ymax);
2419
2420 /* Clamp coordinates. */
2421 rectf.xmin = max_ff(rectf.xmin, 0.0f);
2422 rectf.ymin = max_ff(rectf.ymin, 0.0f);
2423 rectf.xmax = min_ff(rectf.xmax, 1.0f);
2424 rectf.ymax = min_ff(rectf.ymax, 1.0f);
2425
2426 if (rectf.xmin < rectf.xmax && rectf.ymin < rectf.ymax) {
2427 btree->viewer_border = rectf;
2428
2429 if (rectf.xmin == 0.0f && rectf.ymin == 0.0f && rectf.xmax == 1.0f && rectf.ymax == 1.0f) {
2430 btree->flag &= ~NTREE_VIEWER_BORDER;
2431 }
2432 else {
2433 btree->flag |= NTREE_VIEWER_BORDER;
2434 }
2435
2436 ED_node_tree_propagate_change(C, bmain, btree);
2438 }
2439 else {
2440 btree->flag &= ~NTREE_VIEWER_BORDER;
2441 }
2442 }
2443
2444 BKE_image_release_ibuf(ima, ibuf, lock);
2445
2446 return OPERATOR_FINISHED;
2447}
2448
2450{
2451 /* identifiers */
2452 ot->name = "Viewer Region";
2453 ot->description = "Set the boundaries for viewer operations";
2454 ot->idname = "NODE_OT_viewer_border";
2455
2456 /* api callbacks */
2462
2463 /* flags */
2465
2466 /* properties */
2468}
2469
2471{
2472 SpaceNode *snode = CTX_wm_space_node(C);
2473 bNodeTree *btree = snode->nodetree;
2474
2475 btree->flag &= ~NTREE_VIEWER_BORDER;
2478
2479 return OPERATOR_FINISHED;
2480}
2481
2483{
2484 /* identifiers */
2485 ot->name = "Clear Viewer Region";
2486 ot->description = "Clear the boundaries for viewer operations";
2487 ot->idname = "NODE_OT_clear_viewer_border";
2488
2489 /* api callbacks */
2492
2493 /* flags */
2495}
2496
2499/* -------------------------------------------------------------------- */
2504{
2505 SpaceNode *snode = CTX_wm_space_node(C);
2506 PointerRNA ptr = CTX_data_pointer_get(C, "node");
2507 bNodeTree *ntree = nullptr;
2508 bNode *node = nullptr;
2509
2510 if (ptr.data) {
2511 node = (bNode *)ptr.data;
2512 ntree = (bNodeTree *)ptr.owner_id;
2513 }
2514 else if (snode && snode->edittree) {
2515 ntree = snode->edittree;
2516 node = bke::node_get_active(snode->edittree);
2517 }
2518
2519 if (!node || node->type != CMP_NODE_CRYPTOMATTE_LEGACY) {
2520 return OPERATOR_CANCELLED;
2521 }
2522
2524
2526
2527 return OPERATOR_FINISHED;
2528}
2529
2531{
2532 /* identifiers */
2533 ot->name = "Add Cryptomatte Socket";
2534 ot->description = "Add a new input layer to a Cryptomatte node";
2535 ot->idname = "NODE_OT_cryptomatte_layer_add";
2536
2537 /* callbacks */
2540
2541 /* flags */
2543}
2544
2547/* -------------------------------------------------------------------- */
2552{
2553 SpaceNode *snode = CTX_wm_space_node(C);
2554 PointerRNA ptr = CTX_data_pointer_get(C, "node");
2555 bNodeTree *ntree = nullptr;
2556 bNode *node = nullptr;
2557
2558 if (ptr.data) {
2559 node = (bNode *)ptr.data;
2560 ntree = (bNodeTree *)ptr.owner_id;
2561 }
2562 else if (snode && snode->edittree) {
2563 ntree = snode->edittree;
2564 node = bke::node_get_active(snode->edittree);
2565 }
2566
2567 if (!node || node->type != CMP_NODE_CRYPTOMATTE_LEGACY) {
2568 return OPERATOR_CANCELLED;
2569 }
2570
2571 if (!ntreeCompositCryptomatteRemoveSocket(ntree, node)) {
2572 return OPERATOR_CANCELLED;
2573 }
2574
2576
2577 return OPERATOR_FINISHED;
2578}
2579
2581{
2582 /* identifiers */
2583 ot->name = "Remove Cryptomatte Socket";
2584 ot->description = "Remove layer from a Cryptomatte node";
2585 ot->idname = "NODE_OT_cryptomatte_layer_remove";
2586
2587 /* callbacks */
2590
2591 /* flags */
2593}
2594
2597} // namespace blender::ed::space_node
void BKE_callback_exec_id(Main *bmain, ID *id, eCbEvent evt)
Definition callbacks.cc:44
@ BKE_CB_EVT_COMPOSITE_PRE
@ BKE_CB_EVT_COMPOSITE_CANCEL
@ BKE_CB_EVT_COMPOSITE_POST
PointerRNA CTX_data_pointer_get(const bContext *C, const char *member)
WorkSpace * CTX_wm_workspace(const bContext *C)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
SpaceNode * CTX_wm_space_node(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
@ G_DEBUG
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
Image * BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
@ LIB_ID_COPY_DEFAULT
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
General operations, lookup, etc. for materials.
struct Material * BKE_material_default_surface(void)
struct Material * BKE_material_default_volume(void)
#define SH_NODE_OUTPUT_WORLD
Definition BKE_node.hh:914
#define NODE_GROUP_OUTPUT
Definition BKE_node.hh:806
#define SH_NODE_OUTPUT_MATERIAL
Definition BKE_node.hh:913
#define FOREACH_NODETREE_END
Definition BKE_node.hh:870
#define NODE_GROUP
Definition BKE_node.hh:800
#define FOREACH_NODETREE_BEGIN(bmain, _nodetree, _id)
Definition BKE_node.hh:860
#define NODE_FRAME
Definition BKE_node.hh:803
#define SH_NODE_OUTPUT_LIGHT
Definition BKE_node.hh:915
#define SH_NODE_OUTPUT_LINESTYLE
Definition BKE_node.hh:973
#define SH_NODE_SCRIPT
Definition BKE_node.hh:954
void BKE_ntree_update_tag_active_output_changed(bNodeTree *ntree)
void BKE_ntree_update_tag_node_mute(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_main_tree(Main *bmain, bNodeTree *ntree, NodeTreeUpdateExtraParams *params)
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2877
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
Definition scene.cc:2976
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE void copy_v3_v3(float r[3], const float a[3])
float BLI_rctf_length_x(const rctf *rect, float x)
Definition rct.c:171
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.c:408
bool BLI_rctf_isect_pt(const struct rctf *rect, float x, float y)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b)
Definition rct.c:193
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size)
Definition rct.c:462
float BLI_rctf_length_y(const rctf *rect, float y)
Definition rct.c:182
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define STRNCPY_UTF8(dst, src)
#define CLAMP(a, b, c)
#define ELEM(...)
#define STREQ(a, b)
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ DAG_EVAL_RENDER
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:273
void DEG_evaluate_on_refresh(Depsgraph *graph, DepsgraphEvaluateSyncWriteback sync_writeback=DEG_EVALUATE_SYNC_WRITEBACK_NO)
void DEG_graph_build_for_compositor_preview(Depsgraph *graph, bNodeTree *nodetree)
void DEG_debug_name_set(Depsgraph *depsgraph, const char *name)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
ID * DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_NTREE_OUTPUT
Definition DNA_ID.h:1122
@ ID_TAG_DOIT
Definition DNA_ID.h:1003
@ ID_IM
@ ID_LA
@ ID_WO
@ ID_MA
#define MAX_NAME
Definition DNA_defs.h:50
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ NTREE_TEXTURE
@ NTREE_SHADER
@ NTREE_GEOMETRY
@ NTREE_COMPOSIT
@ NODE_TEST
@ NODE_OPTIONS
@ NODE_DO_OUTPUT
@ NODE_HIDDEN
@ NODE_ACTIVE
@ NODE_ACTIVE_TEXTURE
@ NODE_DO_OUTPUT_RECALC
@ NODE_CUSTOM_COLOR
@ NODE_MUTED
@ NODE_SELECT
@ NODE_PREVIEW
@ NODE_LINK_INSERT_TARGET_INVALID
@ CMP_NODE_CRYPTOMATTE_SOURCE_RENDER
@ NTREE_VIEWER_BORDER
eNodeSocketInOut
@ SOCK_OUT
@ SOCK_IN
@ SOCK_IS_LINKED
@ SOCK_MULTI_INPUT
@ SOCK_HIDDEN
@ OB_VOLUME
@ R_MULTIVIEW
@ R_NO_FRAME_UPDATE
@ SCE_COMPOSITOR_DEVICE_GPU
@ SN_OVERLAY_SHOW_PREVIEWS
@ SN_OVERLAY_SHOW_OVERLAYS
@ SNODE_PIN
@ SNODE_BACKDRAW
@ SPACE_NODE
@ SPACE_IMAGE
@ USER_DUP_NTREE
#define UI_SCALE_FAC
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_space_image_sync(Main *bmain, Image *image, bool ignore_render_viewer)
Definition image_edit.cc:70
void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *ntree)
Definition node_edit.cc:492
bool ED_node_is_compositor(const SpaceNode *snode)
Definition node_edit.cc:523
void ED_node_post_apply_transform(bContext *C, bNodeTree *ntree)
Definition node_edit.cc:871
bool ED_node_supports_preview(SpaceNode *snode)
Definition node_edit.cc:543
void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
Definition space_node.cc:66
void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
bool ED_operator_node_editable(bContext *C)
bool ED_operator_node_active(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
int GPU_max_texture_size()
void GPU_material_free(ListBase *gpumaterial)
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
struct blender::bke::bNodeTreeType * ntreeType_Shader
struct blender::bke::bNodeTreeType * ntreeType_Texture
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1663
float UI_view2d_scale_get_x(const View2D *v2d)
Definition view2d.cc:1916
@ WM_JOB_TYPE_COMPOSITE
Definition WM_api.hh:1577
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1565
@ WM_JOB_PROGRESS
Definition WM_api.hh:1566
#define NC_WORLD
Definition WM_types.hh:354
#define ND_SHADING
Definition WM_types.hh:444
#define ND_WORLD
Definition WM_types.hh:419
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_NODE
Definition WM_types.hh:361
#define NC_ANIMATION
Definition WM_types.hh:355
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#define ND_DISPLAY
Definition WM_types.hh:458
#define ND_COMPO_RESULT
Definition WM_types.hh:414
#define NC_SCENE
Definition WM_types.hh:345
#define ND_NODES
Definition WM_types.hh:403
#define ND_MODIFIER
Definition WM_types.hh:429
#define NA_EDITED
Definition WM_types.hh:550
#define NC_MATERIAL
Definition WM_types.hh:347
#define NC_LAMP
Definition WM_types.hh:349
#define NC_IMAGE
Definition WM_types.hh:351
#define NC_TEXTURE
Definition WM_types.hh:348
#define ND_LIGHTING
Definition WM_types.hh:450
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
#define NC_OBJECT
Definition WM_types.hh:346
#define ND_ANIMCHAN
Definition WM_types.hh:463
volatile int lock
unsigned int U
Definition btGjkEpa3.h:78
#define output
bool is_empty() const
Definition BLI_array.hh:253
KeyIterator keys() const
Definition BLI_map.hh:837
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:531
ValueIterator values() const
Definition BLI_map.hh:846
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:582
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:241
ItemIterator items() const
Definition BLI_map.hh:864
bool is_empty() const
Definition BLI_map.hh:937
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
void add_new(const Key &key)
bool contains(const Key &key) const
virtual const int & get_corresponding_output_id(const bNode &input_bnode) const =0
Map< bNodeInstanceKey, timeit::Nanoseconds > & get_nodes_evaluation_times()
Definition profiler.cc:18
#define printf
#define SELECT
KDTree_3d * tree
draw_view in_light_buf[] float
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
RenderEngineType * RE_engines_find(const char *idname)
RenderEngine * RE_engine_create(RenderEngineType *type)
void RE_engine_free(RenderEngine *engine)
#define GS(x)
Definition iris.cc:202
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define G(x, y, z)
const bNodeZoneType * zone_type_by_node_type(const int node_type)
void node_attach_node(bNodeTree *ntree, bNode *node, bNode *parent)
Definition node.cc:3107
void node_set_active(bNodeTree *ntree, bNode *node)
Definition node.cc:3896
void node_detach_node(bNodeTree *ntree, bNode *node)
Definition node.cc:3122
bool node_link_is_hidden(const bNodeLink *link)
Definition node.cc:2993
bNodeTree * node_tree_copy_tree(Main *bmain, const bNodeTree *ntree)
Definition node.cc:3255
bNodeTree * node_tree_localize(bNodeTree *ntree, ID *new_owner_id)
Definition node.cc:3750
bNode * node_add_static_node(const bContext *C, bNodeTree *ntree, int type)
Definition node.cc:2642
void node_remove_node(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
Definition node.cc:3545
void node_internal_relink(bNodeTree *ntree, bNode *node)
Definition node.cc:3019
bNode * node_copy_with_mapping(bNodeTree *dst_tree, const bNode &node_src, int flag, bool use_unique, Map< const bNodeSocket *, bNodeSocket * > &new_socket_map)
Definition node.cc:2696
Span< int > all_zone_output_node_types()
bNodeLink * node_add_link(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
Definition node.cc:2912
void node_tree_local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
Definition node.cc:3793
bNode * node_get_active(bNodeTree *ntree)
Definition node.cc:3849
bNodeTree * node_tree_add_tree_embedded(Main *bmain, ID *owner_id, const char *name, const char *idname)
Definition node.cc:3239
void node_tree_free_tree(bNodeTree *ntree)
Definition node.cc:3626
bool node_set_selected(bNode *node, bool select)
Definition node.cc:3863
Span< int > all_zone_input_node_types()
bool node_tree_contains_tree(const bNodeTree *tree_to_search_in, const bNodeTree *tree_to_search_for)
Definition node.cc:3827
bool node_declaration_ensure(bNodeTree *ntree, bNode *node)
Definition node.cc:3992
bNodeTreeType * node_tree_type_find(const char *idname)
Definition node.cc:1621
bNodeSocket * node_find_socket(bNode *node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:1829
void node_unique_name(bNodeTree *ntree, bNode *node)
Definition node.cc:2593
static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *)
void NODE_OT_delete(wmOperatorType *ot)
static int viewer_border_exec(bContext *C, wmOperator *op)
void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot)
static int clear_viewer_border_exec(bContext *C, wmOperator *)
static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree)
Definition node_edit.cc:458
float node_socket_calculate_height(const bNodeSocket &socket)
Definition node_edit.cc:108
void NODE_OT_read_viewlayers(wmOperatorType *ot)
int node_get_resize_cursor(NodeResizeDirection directions)
static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag)
static bool node_shader_script_update_text_recursive(RenderEngine *engine, RenderEngineType *type, bNodeTree *ntree, Text *text, VectorSet< bNodeTree * > &done_trees)
void tree_draw_order_update(bNodeTree &ntree)
Definition node_draw.cc:302
static bool cursor_isect_multi_input_socket(const float2 &cursor, const bNodeSocket &socket)
static bool node_shader_script_update_poll(bContext *C)
static void node_resize_exit(bContext *C, wmOperator *op, bool cancel)
Definition node_edit.cc:946
static void node_resize_cancel(bContext *C, wmOperator *op)
static int node_hide_toggle_exec(bContext *C, wmOperator *)
static void compo_redrawjob(void *cjv)
Definition node_edit.cc:202
static void compo_statsdrawjob(void *cjv, const char *)
Definition node_edit.cc:194
void NODE_OT_node_copy_color(wmOperatorType *ot)
bool composite_node_editable(bContext *C)
Definition node_edit.cc:447
void NODE_OT_viewer_border(wmOperatorType *ot)
void node_select_paired(bNodeTree &node_tree)
static int node_duplicate_exec(bContext *C, wmOperator *op)
bNodeSocket * node_find_indicated_socket(SpaceNode &snode, ARegion &region, const float2 &cursor, const eNodeSocketInOut in_out)
static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *)
int node_render_changed_exec(bContext *C, wmOperator *)
static int node_preview_toggle_exec(bContext *C, wmOperator *)
static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Array< bNode * > tree_draw_order_calc_nodes_reversed(bNodeTree &ntree)
Definition node_draw.cc:326
void NODE_OT_deactivate_viewer(wmOperatorType *ot)
static int node_options_toggle_exec(bContext *C, wmOperator *)
static int node_deactivate_viewer_exec(bContext *C, wmOperator *)
float2 node_link_calculate_multi_input_position(const float2 &socket_position, const int index, const int total_inputs)
Definition node_edit.cc:118
void NODE_OT_resize(wmOperatorType *ot)
void NODE_OT_render_changed(wmOperatorType *ot)
static void compo_updatejob(void *)
Definition node_edit.cc:266
static void node_duplicate_reparent_recursive(bNodeTree *ntree, const Map< bNode *, bNode * > &node_map, bNode *node)
static void compo_freejob(void *cjv)
Definition node_edit.cc:209
static bool node_previewable(bContext *C)
void NODE_OT_delete_reconnect(wmOperatorType *ot)
void NODE_OT_shader_script_update(wmOperatorType *ot)
void NODE_OT_hide_socket_toggle(wmOperatorType *ot)
void node_set_hidden_sockets(bNode *node, int set)
bool node_is_previewable(const SpaceNode &snode, const bNodeTree &ntree, const bNode &node)
static int node_socket_toggle_exec(bContext *C, wmOperator *)
void remap_node_pairing(bNodeTree &dst_tree, const Map< const bNode *, bNode * > &node_map)
float node_link_dim_factor(const View2D &v2d, const bNodeLink &link)
static void compo_canceljob(void *cjv)
Definition node_edit.cc:321
void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot)
static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
static void viewer_border_corner_to_backdrop(SpaceNode *snode, ARegion *region, int x, int y, int backdrop_width, int backdrop_height, float *fx, float *fy)
bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_edit.cc:968
static int node_read_viewlayers_exec(bContext *C, wmOperator *)
static void compo_progressjob(void *cjv, float progress)
Definition node_edit.cc:271
VectorSet< bNode * > get_selected_nodes(bNodeTree &node_tree)
static void compo_startjob(void *cjv, wmJobWorkerStatus *worker_status)
Definition node_edit.cc:279
static int compo_get_recalc_flags(const bContext *C)
Definition node_edit.cc:148
static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *)
void NODE_OT_preview_toggle(wmOperatorType *ot)
void NODE_OT_clear_viewer_border(wmOperatorType *ot)
static int node_shader_script_update_exec(bContext *C, wmOperator *op)
static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
Definition node_edit.cc:127
static int node_mute_exec(bContext *C, wmOperator *)
static bool compo_breakjob(void *cjv)
Definition node_edit.cc:181
void snode_set_context(const bContext &C)
Definition node_edit.cc:678
void NODE_OT_duplicate(wmOperatorType *ot)
NodeResizeDirection node_get_resize_direction(const SpaceNode &snode, const bNode *node, const int x, const int y)
Definition drawnode.cc:227
bool node_has_hidden_sockets(bNode *node)
void NODE_OT_output_file_add_socket(wmOperatorType *ot)
void NODE_OT_options_toggle(wmOperatorType *ot)
bool composite_node_active(bContext *C)
Definition node_edit.cc:436
static bool socket_is_occluded(const float2 &location, const bNode &node_the_socket_belongs_to, const Span< bNode * > sorted_nodes)
Definition node_edit.cc:888
static int node_delete_exec(bContext *C, wmOperator *)
static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
static void node_resize_init(bContext *C, wmOperator *op, const float2 &cursor, const bNode *node, NodeResizeDirection dir)
Definition node_edit.cc:922
static void compo_initjob(void *cjv)
Definition node_edit.cc:228
static void compo_completejob(void *cjv)
Definition node_edit.cc:332
void NODE_OT_hide_toggle(wmOperatorType *ot)
static int node_copy_color_exec(bContext *C, wmOperator *)
void update_multi_input_indices_for_removed_links(bNode &node)
void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot)
static int node_delete_reconnect_exec(bContext *C, wmOperator *)
void NODE_OT_output_file_move_active_socket(wmOperatorType *ot)
void NODE_OT_mute_toggle(wmOperatorType *ot)
void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node)
bNode * find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snode)
T distance(const T &a, const T &b)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
bNodeSocket * ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
bNodeSocket * ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, const char *name, const ImageFormatData *im_format)
void ntreeCompositExecTree(Render *render, Scene *scene, bNodeTree *ntree, RenderData *rd, const char *view_name, blender::realtime_compositor::RenderContext *render_context, blender::realtime_compositor::Profiler *profiler)
void ntreeCompositTagRender(Scene *scene)
blender::bke::bNodeTreeType * ntreeType_Composite
void ED_node_texture_default(const bContext *C, Tex *tex)
Definition node_edit.cc:648
void ED_node_set_tree_type(SpaceNode *snode, blender::bke::bNodeTreeType *typeinfo)
Definition node_edit.cc:513
void ED_node_composit_default(const bContext *C, Scene *sce)
Definition node_edit.cc:618
bool ED_node_is_compositor(const SpaceNode *snode)
Definition node_edit.cc:523
void ED_node_set_active(Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
Definition node_edit.cc:722
static bool is_compositing_possible(const bContext *C)
Definition node_edit.cc:352
bool ED_node_is_shader(SpaceNode *snode)
Definition node_edit.cc:528
void ED_node_composite_job(const bContext *C, bNodeTree *nodetree, Scene *scene_owner)
Definition node_edit.cc:375
bool ED_node_is_geometry(SpaceNode *snode)
Definition node_edit.cc:538
bool ED_node_supports_preview(SpaceNode *snode)
Definition node_edit.cc:543
void ED_node_shader_default(const bContext *C, ID *id)
Definition node_edit.cc:549
bool ED_node_is_texture(SpaceNode *snode)
Definition node_edit.cc:533
void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree)
Definition node_edit.cc:492
void ED_node_post_apply_transform(bContext *, bNodeTree *)
Definition node_edit.cc:871
blender::bke::bNodeTreeType * ntreeType_Geometry
#define NODE_MULTI_INPUT_LINK_GAP
#define NODE_SOCKSIZE
#define NODE_SOCKSIZE_DRAW_MULIPLIER
#define NODE_DY
float distance(float a, float b)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Render * RE_NewInteractiveCompositorRender(const Scene *scene)
void RE_system_gpu_context_ensure(Render *re)
bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
#define FLT_MAX
Definition stdcycles.h:14
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
void * last
ListBase scenes
Definition BKE_main.hh:210
ListBase materials
Definition BKE_main.hh:216
ListBase worlds
Definition BKE_main.hh:224
struct bNodeTree * nodetree
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
struct ReportList * reports
Definition RE_engine.h:147
struct bNodeTree * nodetree
struct RenderData r
ListBase view_layers
struct Image * image
char tree_idname[64]
struct ID * from
ListBase treepath
struct bNodeTree * edittree
struct ID * id
SpaceNodeOverlay overlay
struct bNodeTree * nodetree
struct bNodeTree * nodetree
char name[64]
ViewerPath viewer_path
bNodeSocketRuntimeHandle * runtime
struct bNodeSocket * next
struct bNodeSocket * prev
void * default_value
bNodeTreeRuntimeHandle * runtime
char idname[64]
ListBase nodes
ListBase links
struct ID * id
float color[3]
struct bNode * parent
bool(* poll)(const bContext *C, bNodeTreeType *ntreetype)
Definition BKE_node.hh:463
void(* get_from_context)(const bContext *C, bNodeTreeType *ntreetype, bNodeTree **r_ntree, ID **r_id, ID **r_from)
Definition BKE_node.hh:465
realtime_compositor::Profiler profiler
Definition node_edit.cc:105
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
short val
Definition WM_types.hh:724
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct PointerRNA * ptr
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
void WM_report(eReportType type, const char *message)
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_mousemove(wmWindow *win)
@ RIGHTMOUSE
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
@ EVT_ESCKEY
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:352
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:455
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:189
void WM_jobs_callbacks_ex(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *), void(*completed)(void *), void(*canceled)(void *))
Definition wm_jobs.cc:373
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336
void WM_operator_properties_border_to_rcti(wmOperator *op, rcti *r_rect)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
void WM_operator_properties_free(PointerRNA *ptr)
bScreen * WM_window_get_active_screen(const wmWindow *win)