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
8
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/* -------------------------------------------------------------------- */
81
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
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
343
344} // namespace blender::ed::space_node
345
346/* -------------------------------------------------------------------- */
349
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. */
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
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
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;
413
414 /* Set up job. */
421 nullptr,
424
426}
427
429
430namespace blender::ed::space_node {
431
432/* -------------------------------------------------------------------- */
435
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
485
486} // namespace blender::ed::space_node
487
488/* -------------------------------------------------------------------- */
491
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{
525 return STREQ(snode->tree_idname, ntreeType_Composite->idname);
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{
540 return STREQ(snode->tree_idname, ntreeType_Geometry->idname);
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
587 shader,
588 blender::bke::node_find_socket(shader, SOCK_OUT, "Background"),
589 output,
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 {
599 shader,
600 blender::bke::node_find_socket(shader, SOCK_OUT, "Emission"),
601 output,
603 }
604
605 shader->locx = 10.0f;
606 shader->locy = 300.0f;
607 output->locx = 300.0f;
608 output->locy = 300.0f;
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
632 out->locx = 200.0f;
633 out->locy = 200.0f;
634
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
661 out->locx = 300.0f;
662 out->locy = 300.0f;
663
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
881
882namespace blender::ed::space_node {
883
884/* -------------------------------------------------------------------- */
887
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
909
910/* -------------------------------------------------------------------- */
913
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 */
1109 ot->invoke = node_resize_invoke;
1110 ot->modal = node_resize_modal;
1112 ot->cancel = node_resize_cancel;
1113
1114 /* flags */
1115 ot->flag = OPTYPE_BLOCKING;
1116}
1117
1119
1120/* -------------------------------------------------------------------- */
1123
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
1282
1283/* -------------------------------------------------------------------- */
1286
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
1316
1317/* -------------------------------------------------------------------- */
1320
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
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 */
1500 ot->exec = node_duplicate_exec;
1502
1503 /* flags */
1504 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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
1561 ot->poll = composite_node_active;
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
1610 ot->poll = composite_node_active;
1611
1612 /* flags */
1613 ot->flag = 0;
1614}
1615
1617
1618/* -------------------------------------------------------------------- */
1621
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 */
1696 ot->exec = node_hide_toggle_exec;
1698
1699 /* flags */
1700 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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{
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 */
1739 ot->poll = node_previewable;
1740
1741 /* flags */
1742 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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 */
1782 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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 */
1813 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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 */
1865 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1866}
1867
1869
1870/* -------------------------------------------------------------------- */
1873
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
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 */
1901 ot->exec = node_mute_exec;
1903
1904 /* flags */
1905 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1906}
1907
1909
1910/* -------------------------------------------------------------------- */
1913
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
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 */
1943 ot->exec = node_delete_exec;
1945
1946 /* flags */
1947 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1948}
1949
1951
1952/* -------------------------------------------------------------------- */
1955
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
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 */
1994 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1995}
1996
1998
1999/* -------------------------------------------------------------------- */
2002
2004{
2005 Scene *scene = CTX_data_scene(C);
2006 SpaceNode *snode = CTX_wm_space_node(C);
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 */
2045 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2046
2048 ot->srna, "file_path", "Image", MAX_NAME, "File Path", "Subpath of the output file");
2049}
2050
2052
2053/* -------------------------------------------------------------------- */
2056
2058{
2059 SpaceNode *snode = CTX_wm_space_node(C);
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 */
2098 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2099}
2100
2102
2103/* -------------------------------------------------------------------- */
2106
2108{
2109 SpaceNode *snode = CTX_wm_space_node(C);
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
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 */
2173 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2174
2175 RNA_def_enum(ot->srna, "direction", direction_items, 2, "Direction", "");
2176}
2177
2179
2180/* -------------------------------------------------------------------- */
2183
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 */
2219 ot->exec = node_copy_color_exec;
2221
2222 /* flags */
2223 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2224}
2225
2227
2228/* -------------------------------------------------------------------- */
2231
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) {
2252
2253 if (node->id || nss->filepath[0]) {
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 */
2368 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2369}
2370
2372
2373/* -------------------------------------------------------------------- */
2376
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 */
2457 ot->invoke = WM_gesture_box_invoke;
2458 ot->exec = viewer_border_exec;
2459 ot->modal = WM_gesture_box_modal;
2460 ot->cancel = WM_gesture_box_cancel;
2461 ot->poll = composite_node_active;
2462
2463 /* flags */
2464 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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 */
2491 ot->poll = composite_node_active;
2492
2493 /* flags */
2494 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2495}
2496
2498
2499/* -------------------------------------------------------------------- */
2502
2504{
2505 SpaceNode *snode = CTX_wm_space_node(C);
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 */
2542 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2543}
2544
2546
2547/* -------------------------------------------------------------------- */
2550
2552{
2553 SpaceNode *snode = CTX_wm_space_node(C);
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 */
2592 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2593}
2594
2596
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)
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
@ LIB_ID_COPY_DEFAULT
General operations, lookup, etc. for materials.
struct Material * BKE_material_default_surface(void)
struct Material * BKE_material_default_volume(void)
#define CMP_NODE_COMPOSITE
Definition BKE_node.hh:1033
#define SH_NODE_OUTPUT_WORLD
Definition BKE_node.hh:914
#define CMP_NODE_VIEWER
Definition BKE_node.hh:1012
#define SH_NODE_EMISSION
Definition BKE_node.hh:927
#define CMP_NODE_CRYPTOMATTE
Definition BKE_node.hh:1111
#define GEO_NODE_VIEWER
Definition BKE_node.hh:1201
#define NODE_GROUP_OUTPUT
Definition BKE_node.hh:806
#define TEX_NODE_CHECKER
Definition BKE_node.hh:1136
#define CMP_NODE_CRYPTOMATTE_LEGACY
Definition BKE_node.hh:1108
#define SH_NODE_OUTPUT_MATERIAL
Definition BKE_node.hh:913
#define CMP_NODE_OUTPUT_FILE
Definition BKE_node.hh:1034
#define FOREACH_NODETREE_END
Definition BKE_node.hh:870
#define SH_NODE_BACKGROUND
Definition BKE_node.hh:919
#define NODE_GROUP
Definition BKE_node.hh:800
#define TEX_NODE_OUTPUT
Definition BKE_node.hh:1135
#define FOREACH_NODETREE_BEGIN(bmain, _nodetree, _id)
Definition BKE_node.hh:860
#define NODE_FRAME
Definition BKE_node.hh:803
#define CMP_NODE_R_LAYERS
Definition BKE_node.hh:1032
#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
@ CMP_NODE_CRYPTOMATTE_SOURCE_RENDER
@ 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
eNodeSocketInOut
@ SOCK_OUT
@ SOCK_IN
@ NTREE_VIEWER_BORDER
@ SOCK_IS_LINKED
@ SOCK_MULTI_INPUT
@ SOCK_HIDDEN
@ NTREE_TEXTURE
@ NTREE_SHADER
@ NTREE_GEOMETRY
@ NTREE_COMPOSIT
@ NODE_LINK_INSERT_TARGET_INVALID
@ 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
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between world
struct blender::bke::bNodeTreeType * ntreeType_Texture
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
#define C
Definition RandGen.cpp:29
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
#define NC_NODE
Definition WM_types.hh:361
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_ANIMATION
Definition WM_types.hh:355
#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
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#define NC_OBJECT
Definition WM_types.hh:346
#define ND_ANIMCHAN
Definition WM_types.hh:463
volatile int lock
#define U
#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
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
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
#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)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
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
#define USE_ESC_COMPO
Definition node_edit.cc:76
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
int tag
Definition DNA_ID.h:434
char name[66]
Definition DNA_ID.h:425
void * last
void * first
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
char engine[32]
struct ImageFormatData im_format
void(* update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node)
Definition RE_engine.h:112
struct ReportList * reports
Definition RE_engine.h:147
struct bNodeTree * nodetree
SceneRuntimeHandle * runtime
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
bNodeTypeHandle * typeinfo
int16_t custom1
float locy
float width
ListBase inputs
float height
struct ID * id
float color[3]
struct bNode * parent
float locx
void * storage
float offsetx
ListBase outputs
float offsety
int16_t type
ListBase areabase
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
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)