Blender V5.0
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#include <optional>
11
12#include "MEM_guardedalloc.h"
13
14#include "DNA_material_types.h"
15#include "DNA_node_types.h"
16#include "DNA_text_types.h"
17#include "DNA_world_types.h"
18
19#include "BKE_callbacks.hh"
20#include "BKE_context.hh"
21#include "BKE_global.hh"
22#include "BKE_image.hh"
23#include "BKE_lib_id.hh"
24#include "BKE_main.hh"
26#include "BKE_material.hh"
27#include "BKE_node.hh"
29#include "BKE_node_runtime.hh"
31#include "BKE_report.hh"
32#include "BKE_scene.hh"
33#include "BKE_scene_runtime.hh"
34#include "BKE_screen.hh"
35
36#include "BLI_listbase.h"
37#include "BLI_math_vector.h"
38#include "BLI_math_vector.hh"
39#include "BLI_string.h"
40#include "BLI_string_utf8.h"
41#include "BLI_utildefines.h"
42
43#include "BLT_translation.hh"
44
45#include "DEG_depsgraph.hh"
49
51#include "RE_engine.h"
52#include "RE_pipeline.h"
53
54#include "ED_image.hh"
55#include "ED_node.hh" /* own include */
56#include "ED_render.hh"
57#include "ED_screen.hh"
58#include "ED_viewer_path.hh"
59
60#include "RNA_access.hh"
61#include "RNA_define.hh"
62#include "RNA_prototypes.hh"
63
64#include "WM_api.hh"
65#include "WM_types.hh"
66
67#include "UI_view2d.hh"
68
69#include "GPU_capabilities.hh"
70#include "GPU_material.hh"
71
72#include "IMB_imbuf_types.hh"
73
74#include "NOD_composite.hh"
75#include "NOD_geometry.hh"
76#include "NOD_shader.h"
77#include "NOD_socket.hh"
78#include "NOD_texture.h"
79#include "node_intern.hh" /* own include */
80
81#include "COM_compositor.hh"
82#include "COM_context.hh"
83#include "COM_profiler.hh"
84
86
87#define USE_ESC_COMPO
88
89/* -------------------------------------------------------------------- */
92
93struct CompoJob {
94 /* Input parameters. */
99 /* Evaluated state/ */
102 /* Render instance. */
104 /* Job system integration. */
105 const bool *stop;
107 float *progress;
109
112};
113
115{
116 float sock_height = NODE_SOCKSIZE;
117 if (socket.flag & SOCK_MULTI_INPUT) {
118 sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket.runtime->total_inputs,
120 }
121 return sock_height;
122}
123
125 const int index,
126 const int total_inputs)
127{
128 const float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) *
129 0.5f;
130 return {socket_position.x, socket_position.y - offset + index * NODE_MULTI_INPUT_LINK_GAP};
131}
132
133/* Called by compositor, only to check job 'stop' value. */
134static bool compo_breakjob(void *cjv)
135{
136 CompoJob *cj = (CompoJob *)cjv;
137
138 /* Without G.is_break 'ESC' won't quit - which annoys users. */
139 return (*(cj->stop)
140#ifdef USE_ESC_COMPO
141 || G.is_break
142#endif
143 );
144}
145
146/* Called by compositor, #wmJob sends notifier. */
147static void compo_statsdrawjob(void *cjv, const char * /*str*/)
148{
149 CompoJob *cj = (CompoJob *)cjv;
150
151 *(cj->do_update) = true;
152}
153
154/* Called by compositor, wmJob sends notifier. */
155static void compo_redrawjob(void *cjv)
156{
157 CompoJob *cj = (CompoJob *)cjv;
158
159 *(cj->do_update) = true;
160}
161
162static void compo_freejob(void *cjv)
163{
164 CompoJob *cj = (CompoJob *)cjv;
165
166 if (cj->localtree) {
167 /* Merge back node previews, only for completed jobs. */
168 if (!cj->cancelled) {
170 }
171
173 MEM_freeN(cj->localtree);
174 }
175
176 MEM_delete(cj);
177}
178
179/* Only now we copy the nodetree, so adding many jobs while
180 * sliding buttons doesn't frustrate. */
181static void compo_initjob(void *cjv)
182{
183 CompoJob *cj = (CompoJob *)cjv;
184 Main *bmain = cj->bmain;
185 Scene *scene = cj->scene;
186 ViewLayer *view_layer = cj->view_layer;
187
188 bke::CompositorRuntime &compositor_runtime = scene->runtime->compositor;
189
190 if (!compositor_runtime.preview_depsgraph) {
191 compositor_runtime.preview_depsgraph = DEG_graph_new(
192 bmain, scene, view_layer, DAG_EVAL_RENDER);
193 DEG_debug_name_set(compositor_runtime.preview_depsgraph, "COMPOSITOR");
194 }
195
196 /* Update the viewer layer of the compositor since it changed since the depsgraph was created. */
197 if (DEG_get_input_view_layer(compositor_runtime.preview_depsgraph) != view_layer) {
198 DEG_graph_replace_owners(compositor_runtime.preview_depsgraph, bmain, scene, view_layer);
200 }
201
202 cj->compositor_depsgraph = compositor_runtime.preview_depsgraph;
204
205 /* NOTE: Don't update animation to preserve unkeyed changes, this means can not use
206 * evaluate_on_framechange. */
208
210
211 cj->localtree = bke::node_tree_localize(ntree_eval, nullptr);
212
216 }
217}
218
219/* Called before redraw notifiers, it moves finished previews over. */
220static void compo_updatejob(void * /*cjv*/)
221{
223}
224
225static void compo_progressjob(void *cjv, float progress)
226{
227 CompoJob *cj = (CompoJob *)cjv;
228
229 *(cj->progress) = progress;
230}
231
232/* Only this runs inside thread. */
233static void compo_startjob(void *cjv, wmJobWorkerStatus *worker_status)
234{
235 CompoJob *cj = (CompoJob *)cjv;
236 bNodeTree *ntree = cj->localtree;
238
239 cj->stop = &worker_status->stop;
240 cj->do_update = &worker_status->do_update;
241 cj->progress = &worker_status->progress;
242
243 ntree->runtime->test_break = compo_breakjob;
244 ntree->runtime->tbh = cj;
245 ntree->runtime->stats_draw = compo_statsdrawjob;
246 ntree->runtime->sdh = cj;
247 ntree->runtime->progress = compo_progressjob;
248 ntree->runtime->prh = cj;
249 ntree->runtime->update_draw = compo_redrawjob;
250 ntree->runtime->udh = cj;
251
253
254 if ((scene->r.scemode & R_MULTIVIEW) == 0) {
255 COM_execute(cj->re, &scene->r, scene, ntree, "", nullptr, &cj->profiler, cj->needed_outputs);
256 }
257 else {
258 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
259 if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) {
260 continue;
261 }
263 cj->re, &scene->r, scene, ntree, srv->name, nullptr, &cj->profiler, cj->needed_outputs);
264 }
265 }
266
267 ntree->runtime->test_break = nullptr;
268 ntree->runtime->stats_draw = nullptr;
269 ntree->runtime->progress = nullptr;
270}
271
272static void compo_canceljob(void *cjv)
273{
274 CompoJob *cj = (CompoJob *)cjv;
275 Main *bmain = cj->bmain;
276 Scene *scene = cj->scene;
278 cj->cancelled = true;
279
280 scene->runtime->compositor.per_node_execution_time = cj->profiler.get_nodes_evaluation_times();
281}
282
283static void compo_completejob(void *cjv)
284{
285 CompoJob *cj = (CompoJob *)cjv;
286 Main *bmain = cj->bmain;
287 Scene *scene = cj->scene;
289
290 scene->runtime->compositor.per_node_execution_time = cj->profiler.get_nodes_evaluation_times();
291}
292
294
295} // namespace blender::ed::space_node
296
297/* -------------------------------------------------------------------- */
300
301/* Identify if the compositor can run. Currently, this only checks if the compositor is set to GPU
302 * and the render size exceeds what can be allocated as a texture in it. */
304{
305 Scene *scene = CTX_data_scene(C);
306 /* CPU compositor can always run. */
308 return true;
309 }
310
311 int width, height;
312 BKE_render_resolution(&scene->r, false, &width, &height);
313 if (!GPU_is_safe_texture_size(width, height)) {
314 WM_global_report(RPT_ERROR, "Render size too large for GPU, use CPU compositor instead");
315 return false;
316 }
317
318 return true;
319}
320
321/* Returns the compositor outputs that need to be computed because their result is visible to the
322 * user. */
324{
326
327 wmWindowManager *window_manager = CTX_wm_manager(C);
328 LISTBASE_FOREACH (wmWindow *, window, &window_manager->windows) {
329 bScreen *screen = WM_window_get_active_screen(window);
330 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
331 SpaceLink *space_link = static_cast<SpaceLink *>(area->spacedata.first);
332 if (!space_link || !ELEM(space_link->spacetype, SPACE_NODE, SPACE_IMAGE)) {
333 continue;
334 }
335 if (space_link->spacetype == SPACE_NODE) {
336 const SpaceNode *space_node = reinterpret_cast<const SpaceNode *>(space_link);
337 if (space_node->flag & SNODE_BACKDRAW) {
339 }
340 if (space_node->overlay.flag & SN_OVERLAY_SHOW_PREVIEWS) {
342 }
343 }
344 else if (space_link->spacetype == SPACE_IMAGE) {
345 const SpaceImage *space_image = reinterpret_cast<const SpaceImage *>(space_link);
346 Image *image = ED_space_image(space_image);
347 if (!image || image->source != IMA_SRC_VIEWER) {
348 continue;
349 }
350 if (image->type == IMA_TYPE_R_RESULT) {
352 }
353 else if (image->type == IMA_TYPE_COMPOSITE) {
355 }
356 }
357
358 /* All outputs are already needed, return early. */
359 if (needed_outputs ==
362 {
363 return needed_outputs;
364 }
365 }
366 }
367
368 return needed_outputs;
369}
370
371void ED_node_composite_job(const bContext *C, bNodeTree *nodetree, Scene *scene_owner)
372{
373 /* None of the outputs are needed except maybe previews, so no need to execute the compositor.
374 * Previews are not considered because they are a secondary output that needs another output to
375 * be computed with. */
377 if (ELEM(needed_outputs,
380 {
381 return;
382 }
383
384 using namespace blender::ed::space_node;
385
386 Main *bmain = CTX_data_main(C);
387 Scene *scene = CTX_data_scene(C);
388 ViewLayer *view_layer = CTX_data_view_layer(C);
389
391 return;
392 }
393
394 /* See #32272. */
395 if (G.is_rendering) {
396 return;
397 }
398
399#ifdef USE_ESC_COMPO
400 G.is_break = false;
401#endif
402
404 scene, BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"), false);
405
408 scene_owner,
409 "Compositing...",
412 CompoJob *cj = MEM_new<CompoJob>("compo job");
413
414 /* Custom data for preview thread. */
415 cj->bmain = bmain;
416 cj->scene = scene;
417 cj->view_layer = view_layer;
418 cj->ntree = nodetree;
419 cj->needed_outputs = needed_outputs;
420
421 /* Set up job. */
428 nullptr,
431
433}
434
436
437namespace blender::ed::space_node {
438
439/* -------------------------------------------------------------------- */
442
444{
446 SpaceNode *snode = CTX_wm_space_node(C);
447 if (ED_node_is_compositor(snode)) {
448 return true;
449 }
450 }
451 return false;
452}
453
455{
457 SpaceNode *snode = CTX_wm_space_node(C);
458 if (ED_node_is_compositor(snode)) {
459 return true;
460 }
461 }
462 return false;
463}
464
466
467} // namespace blender::ed::space_node
468
469/* -------------------------------------------------------------------- */
472
474{
475 if (typeinfo) {
476 STRNCPY_UTF8(snode->tree_idname, typeinfo->idname.c_str());
477 }
478 else {
479 snode->tree_idname[0] = '\0';
480 }
481
482 /* Reset members that store tree type-dependant values. */
483 snode->node_tree_sub_type = 0;
484 snode->selected_node_group = nullptr;
485}
486
488{
489 return snode->tree_idname == ntreeType_Composite->idname;
490}
491
493{
494 return snode->tree_idname == ntreeType_Shader->idname;
495}
496
498{
499 return snode->tree_idname == ntreeType_Texture->idname;
500}
501
503{
504 return snode->tree_idname == ntreeType_Geometry->idname;
505}
506
508{
509 return ED_node_is_compositor(snode) ||
510 (USER_EXPERIMENTAL_TEST(&U, use_shader_node_previews) && ED_node_is_shader(snode));
511}
512
513void ED_node_shader_default(const bContext *C, Main *bmain, ID *id)
514{
515 if (GS(id->name) == ID_MA) {
516 /* Materials */
518 Material *ma = (Material *)id;
519 Material *ma_default;
520
521 if (ob && ob->type == OB_VOLUME) {
522 ma_default = BKE_material_default_volume();
523 }
524 else {
525 ma_default = BKE_material_default_surface();
526 }
527
528 ma->nodetree = blender::bke::node_tree_copy_tree(bmain, *ma_default->nodetree);
529 ma->nodetree->owner_id = &ma->id;
530 for (bNode *node_iter : ma->nodetree->all_nodes()) {
531 STRNCPY_UTF8(node_iter->name, DATA_(node_iter->name));
533 }
534
536 }
537 else if (ELEM(GS(id->name), ID_WO, ID_LA)) {
538 /* Emission */
539 bNode *shader, *output;
541 nullptr, id, "Shader Nodetree", ntreeType_Shader->idname);
542
543 if (GS(id->name) == ID_WO) {
544 World *world = (World *)id;
545 ntree = world->nodetree;
546
550 *shader,
551 *blender::bke::node_find_socket(*shader, SOCK_OUT, "Background"),
552 *output,
554
555 bNodeSocket *color_sock = blender::bke::node_find_socket(*shader, SOCK_IN, "Color");
556 copy_v3_v3(((bNodeSocketValueRGBA *)color_sock->default_value)->value, &world->horr);
557 }
558 else {
559 shader = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_EMISSION);
562 *shader,
563 *blender::bke::node_find_socket(*shader, SOCK_OUT, "Emission"),
564 *output,
566 }
567
568 shader->location[0] = -200.0f;
569 shader->location[1] = 100.0f;
570 output->location[0] = 200.0f;
571 output->location[1] = 100.0f;
574 }
575 else {
576 printf("ED_node_shader_default called on wrong ID type.\n");
577 return;
578 }
579}
580
582{
583 Main *bmain = CTX_data_main(C);
584
585 /* but lets check it anyway */
586 if (sce->compositing_node_group) {
587 if (G.debug & G_DEBUG) {
588 printf("error in composite initialize\n");
589 }
590 return;
591 }
592
594 bmain, DATA_("Compositor Nodes"), ntreeType_Composite->idname);
595
597
599}
600
602{
603 BLI_assert(ntree != nullptr && ntree->type == NTREE_COMPOSIT);
604 BLI_assert(BLI_listbase_count(&ntree->nodes) == 0);
605
606 ntree->tree_interface.add_socket(
607 DATA_("Image"), "", "NodeSocketColor", NODE_INTERFACE_SOCKET_INPUT, nullptr);
608 ntree->tree_interface.add_socket(
609 DATA_("Image"), "", "NodeSocketColor", NODE_INTERFACE_SOCKET_OUTPUT, nullptr);
610
611 bNode *composite = blender::bke::node_add_node(C, *ntree, "NodeGroupOutput");
612 composite->location[0] = 200.0f;
613 composite->location[1] = 0.0f;
614
616 in->location[0] = -150.0f - in->width;
617 in->location[1] = 0.0f;
619 in->flag &= ~NODE_PREVIEW;
620
622 reroute->location[0] = 100.0f;
623 reroute->location[1] = -35.0f;
624
626 viewer->location[0] = 200.0f;
627 viewer->location[1] = -80.0f;
628
629 /* Viewer and Composite nodes are linked to Render Layer's output image socket through a reroute
630 * node. */
632 *in,
633 *(bNodeSocket *)in->outputs.first,
634 *reroute,
635 *(bNodeSocket *)reroute->inputs.first);
636
638 *reroute,
639 *(bNodeSocket *)reroute->outputs.first,
640 *composite,
641 *(bNodeSocket *)composite->inputs.first);
642
644 *reroute,
645 *(bNodeSocket *)reroute->outputs.first,
646 *viewer,
647 *(bNodeSocket *)viewer->inputs.first);
648
650}
651
653{
654 if (tex->nodetree) {
655 if (G.debug & G_DEBUG) {
656 printf("error in texture initialize\n");
657 }
658 return;
659 }
660
662 nullptr, &tex->id, "Texture Nodetree", ntreeType_Texture->idname);
663
665 out->location[0] = 300.0f;
666 out->location[1] = 300.0f;
667
669 in->location[0] = 10.0f;
670 in->location[1] = 300.0f;
672
673 bNodeSocket *fromsock = (bNodeSocket *)in->outputs.first;
674 bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
675 blender::bke::node_add_link(*tex->nodetree, *in, *fromsock, *out, *tosock);
676
678}
679
680namespace blender::ed::space_node {
681
683{
684 /* NOTE: Here we set the active tree(s), even called for each redraw now, so keep it fast :). */
685
686 SpaceNode *snode = CTX_wm_space_node(&C);
688 bNodeTree *ntree = snode->nodetree;
689 ID *id = snode->id, *from = snode->from;
690
691 /* Check the tree type. */
692 if (!treetype || (treetype->poll && !treetype->poll(&C, treetype))) {
693 /* Invalid tree type, skip.
694 * NOTE: not resetting the node path here, invalid #bNodeTreeType
695 * may still be registered at a later point. */
696 return;
697 }
698
699 if (snode->nodetree && !STREQ(snode->nodetree->idname, snode->tree_idname)) {
700 /* Current tree does not match selected type, clear tree path. */
701 ntree = nullptr;
702 id = nullptr;
703 from = nullptr;
704 }
705
706 if (!(snode->flag & SNODE_PIN) || ntree == nullptr) {
707 if (treetype->get_from_context) {
708 /* Reset and update from context. */
709 ntree = nullptr;
710 id = nullptr;
711 from = nullptr;
712
713 treetype->get_from_context(&C, treetype, &ntree, &id, &from);
714 }
715 }
716
717 if (snode->nodetree != ntree || snode->id != id || snode->from != from ||
718 (snode->treepath.last == nullptr && ntree))
719 {
720 ScrArea *area = CTX_wm_area(&C);
722 ED_node_tree_start(region, snode, ntree, id, from);
723 }
724}
725
726} // namespace blender::ed::space_node
727
729 Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
730{
731 if (r_active_texture_changed) {
732 *r_active_texture_changed = false;
733 }
734
735 blender::bke::node_set_active(*ntree, *node);
736 if (node->type_legacy == NODE_GROUP) {
737 return;
738 }
739
740 const bool was_output = (node->flag & NODE_DO_OUTPUT) != 0;
741 bool do_update = false;
742
743 /* Generic node group output: set node as active output. */
744 if (node->is_group_output()) {
745 for (bNode *node_iter : ntree->all_nodes()) {
746 if (node_iter->is_group_output()) {
747 node_iter->flag &= ~NODE_DO_OUTPUT;
748 }
749 }
750
751 node->flag |= NODE_DO_OUTPUT;
752 if (!was_output) {
753 do_update = true;
755 }
756 }
757
758 /* Tree specific activate calls. */
759 if (ntree->type == NTREE_SHADER) {
760 if (ELEM(node->type_legacy,
765 {
766 for (bNode *node_iter : ntree->all_nodes()) {
767 if (node_iter->type_legacy == node->type_legacy) {
768 node_iter->flag &= ~NODE_DO_OUTPUT;
769 }
770 }
771
772 node->flag |= NODE_DO_OUTPUT;
774 }
775
776 BKE_main_ensure_invariants(*bmain, ntree->id);
777
778 if (node->flag & NODE_ACTIVE_TEXTURE) {
779 /* If active texture changed, free GLSL materials. */
780 LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
781 if (ma->nodetree && blender::bke::node_tree_contains_tree(*ma->nodetree, *ntree)) {
782 GPU_material_free(&ma->gpumaterial);
783
784 /* Sync to active texpaint slot, otherwise we can end up painting on a different slot
785 * than we are looking at. */
786 if (ma->texpaintslot) {
787 if (node->id != nullptr && GS(node->id->name) == ID_IM) {
788 Image *image = (Image *)node->id;
789 for (int i = 0; i < ma->tot_slots; i++) {
790 if (ma->texpaintslot[i].ima == image) {
791 ma->paint_active_slot = i;
792 }
793 }
794 }
795 }
796 }
797 }
798
799 LISTBASE_FOREACH (World *, wo, &bmain->worlds) {
800 if (wo->nodetree && blender::bke::node_tree_contains_tree(*wo->nodetree, *ntree)) {
801 GPU_material_free(&wo->gpumaterial);
802 }
803 }
804
805 /* Sync to Image Editor under the following conditions:
806 * - current image is not pinned
807 * - current image is not a Render Result or ViewerNode (want to keep looking at these) */
808 if (node->id != nullptr && GS(node->id->name) == ID_IM) {
809 Image *image = (Image *)node->id;
810 ED_space_image_sync(bmain, image, true);
811 }
812
813 if (r_active_texture_changed) {
814 *r_active_texture_changed = true;
815 }
816 BKE_main_ensure_invariants(*bmain, ntree->id);
818 }
819
821 }
822 else if (ntree->type == NTREE_COMPOSIT) {
823 /* Make active viewer, currently only one is supported. */
824 if (node->type_legacy == CMP_NODE_VIEWER) {
825 for (bNode *node_iter : ntree->all_nodes()) {
826 if (node_iter->type_legacy == CMP_NODE_VIEWER) {
827 node_iter->flag &= ~NODE_DO_OUTPUT;
828 }
829 }
830
831 node->flag |= NODE_DO_OUTPUT;
832 if (was_output == 0) {
834 BKE_main_ensure_invariants(*bmain, ntree->id);
835 }
836 }
837 else if (do_update) {
838 BKE_main_ensure_invariants(*bmain, ntree->id);
839 }
840 }
841 else if (ntree->type == NTREE_GEOMETRY) {
842 if (node->type_legacy == GEO_NODE_VIEWER) {
843 if ((node->flag & NODE_DO_OUTPUT) == 0) {
844 for (bNode *node_iter : ntree->all_nodes()) {
845 if (node_iter->type_legacy == GEO_NODE_VIEWER) {
846 node_iter->flag &= ~NODE_DO_OUTPUT;
847 }
848 }
849 node->flag |= NODE_DO_OUTPUT;
850 }
852 }
853 }
854}
855
857{
858 /* XXX This does not work due to layout functions relying on node->block,
859 * which only exists during actual drawing. Can we rely on valid draw_bounds rects?
860 */
861 /* make sure nodes have correct bounding boxes after transform */
862 // node_update_nodetree(C, ntree, 0.0f, 0.0f);
863}
864
866
867namespace blender::ed::space_node {
868
869/* -------------------------------------------------------------------- */
872
873static bool socket_is_occluded(const float2 &location,
874 const bNode &node_the_socket_belongs_to,
875 const Span<bNode *> sorted_nodes)
876{
877 for (bNode *node : sorted_nodes) {
878 if (node == &node_the_socket_belongs_to) {
879 /* Nodes after this one are underneath and can't occlude the socket. */
880 return false;
881 }
882
883 rctf socket_hitbox;
884 const float socket_hitbox_radius = NODE_SOCKSIZE - 0.1f * U.widget_unit;
885 BLI_rctf_init_pt_radius(&socket_hitbox, location, socket_hitbox_radius);
886 if (BLI_rctf_inside_rctf(&node->runtime->draw_bounds, &socket_hitbox)) {
887 return true;
888 }
889 }
890 return false;
891}
892
894
895/* -------------------------------------------------------------------- */
898
906
908 bContext *C, wmOperator *op, const float2 &cursor, const bNode *node, NodeResizeDirection dir)
909{
910 Scene *scene = CTX_data_scene(C);
912
913 op->customdata = nsw;
914
915 nsw->mxstart = cursor.x;
916 nsw->mystart = cursor.y;
917
918 /* store old */
919 nsw->oldlocx = node->location[0];
920 nsw->oldlocy = node->location[1];
921 nsw->oldwidth = node->width;
922 nsw->oldheight = node->height;
923 nsw->directions = dir;
925
927 /* add modal handler */
929}
930
931static void node_resize_exit(bContext *C, wmOperator *op, bool cancel)
932{
934
936
937 /* Restore old data on cancel. */
938 if (cancel) {
939 SpaceNode *snode = CTX_wm_space_node(C);
940 bNode *node = bke::node_get_active(*snode->edittree);
941
942 node->location[0] = nsw->oldlocx;
943 node->location[1] = nsw->oldlocy;
944 node->width = nsw->oldwidth;
945 node->height = nsw->oldheight;
946 }
947
948 MEM_freeN(nsw);
949 op->customdata = nullptr;
950}
951
952enum class NodeResizeAction : int {
953 Begin = 0,
957};
958
960{
961 static const EnumPropertyItem modal_items[] = {
962 {int(NodeResizeAction::Begin), "BEGIN", 0, "Resize Node", ""},
963 {int(NodeResizeAction::Cancel), "CANCEL", 0, "Cancel", ""},
964 {int(NodeResizeAction::SnapInvertOn), "SNAP_INVERT_ON", 0, "Snap Invert", ""},
965 {int(NodeResizeAction::SnapInvertOff), "SNAP_INVERT_OFF", 0, "Snap Invert", ""},
966 {0, nullptr, 0, nullptr, nullptr},
967 };
968
969 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Node Resize Modal Map");
970
971 if (keymap && keymap->modal_items) {
972 return nullptr;
973 }
974
975 keymap = WM_modalkeymap_ensure(keyconf, "Node Resize Modal Map", modal_items);
976
977 WM_modalkeymap_assign(keymap, "NODE_OT_resize");
978
979 return keymap;
980}
981
982/* Compute the nearest 1D coordinate corresponding to the nearest grid in node editors. */
983static float nearest_node_grid_coord(float co)
984{
985 /* Size and location of nodes are independent of UI scale, so grid size should be independent of
986 * UI scale as well. */
987 float grid_size = grid_size_get() / UI_SCALE_FAC;
988 float rest = fmod(co, grid_size);
989 float offset = rest - grid_size / 2 >= 0 ? grid_size : 0;
990
991 return co - rest + offset;
992}
993
995{
996 SpaceNode *snode = CTX_wm_space_node(C);
997 ARegion *region = CTX_wm_region(C);
998 bNode *node = bke::node_get_active(*snode->edittree);
1000
1001 if (event->type == EVT_MODAL_MAP) {
1002 switch (NodeResizeAction(event->val)) {
1005 }
1007 node_resize_exit(C, op, true);
1008 ED_region_tag_redraw(region);
1009 return OPERATOR_CANCELLED;
1010 }
1013 nsw->snap_to_grid = !nsw->snap_to_grid;
1015 }
1016 }
1017 }
1018
1019 switch (event->type) {
1020 case MOUSEMOVE: {
1021 int2 mval;
1022 WM_event_drag_start_mval(event, region, mval);
1023 float mx, my;
1024 UI_view2d_region_to_view(&region->v2d, mval.x, mval.y, &mx, &my);
1025 const float dx = (mx - nsw->mxstart) / UI_SCALE_FAC;
1026 const float dy = (my - nsw->mystart) / UI_SCALE_FAC;
1027
1028 if (node) {
1029 float *pwidth = &node->width;
1030 float *pheight = &node->height;
1031 float oldwidth = nsw->oldwidth;
1032 float widthmin = node->typeinfo->minwidth;
1033 float widthmax = node->typeinfo->maxwidth;
1034
1035 {
1036 if (nsw->directions & NODE_RESIZE_RIGHT) {
1037 *pwidth = oldwidth + dx;
1038
1039 if (nsw->snap_to_grid) {
1040 *pwidth = nearest_node_grid_coord(*pwidth);
1041 }
1042 CLAMP(*pwidth, widthmin, widthmax);
1043 }
1044 if (nsw->directions & NODE_RESIZE_LEFT) {
1045 float locmax = nsw->oldlocx + oldwidth;
1046 *pwidth = oldwidth - dx;
1047
1048 if (nsw->snap_to_grid) {
1049 *pwidth = nearest_node_grid_coord(*pwidth);
1050 }
1051 CLAMP(*pwidth, widthmin, widthmax);
1052 node->location[0] = locmax - *pwidth;
1053 }
1054 }
1055
1056 /* Height works the other way round. */
1057 {
1058 float heightmin = UI_SCALE_FAC * node->typeinfo->minheight;
1059 float heightmax = UI_SCALE_FAC * node->typeinfo->maxheight;
1060 if (nsw->directions & NODE_RESIZE_TOP) {
1061 float locmin = nsw->oldlocy - nsw->oldheight;
1062 *pheight = nsw->oldheight + dy;
1063
1064 if (nsw->snap_to_grid) {
1065 *pheight = nearest_node_grid_coord(*pheight);
1066 }
1067 CLAMP(*pheight, heightmin, heightmax);
1068 node->location[1] = locmin + *pheight;
1069 }
1070 if (nsw->directions & NODE_RESIZE_BOTTOM) {
1071 *pheight = nsw->oldheight - dy;
1072
1073 if (nsw->snap_to_grid) {
1074 *pheight = nearest_node_grid_coord(*pheight);
1075 }
1076 CLAMP(*pheight, heightmin, heightmax);
1077 }
1078 }
1079 }
1080
1081 ED_region_tag_redraw(region);
1082
1083 break;
1084 }
1085 case LEFTMOUSE:
1086 case MIDDLEMOUSE:
1087 case RIGHTMOUSE: {
1088 if (event->val == KM_RELEASE) {
1089 node_resize_exit(C, op, false);
1091
1092 return OPERATOR_FINISHED;
1093 }
1094 break;
1095 }
1096 default: {
1097 break;
1098 }
1099 }
1100
1102}
1103
1105{
1106 SpaceNode *snode = CTX_wm_space_node(C);
1107 ARegion *region = CTX_wm_region(C);
1108 const bNode *node = bke::node_get_active(*snode->edittree);
1109
1110 if (node == nullptr) {
1112 }
1113
1114 /* Convert mouse coordinates to `v2d` space. */
1115 float2 cursor;
1116 int2 mval;
1117 WM_event_drag_start_mval(event, region, mval);
1118 UI_view2d_region_to_view(&region->v2d, mval.x, mval.y, &cursor.x, &cursor.y);
1119 const NodeResizeDirection dir = node_get_resize_direction(*snode, node, cursor.x, cursor.y);
1120 if (dir == NODE_RESIZE_NONE) {
1122 }
1123
1124 node_resize_init(C, op, cursor, node, dir);
1126}
1127
1129{
1130 node_resize_exit(C, op, true);
1131}
1132
1134{
1135 /* identifiers */
1136 ot->name = "Resize Node";
1137 ot->idname = "NODE_OT_resize";
1138 ot->description = "Resize a node";
1139
1140 /* API callbacks. */
1141 ot->invoke = node_resize_invoke;
1142 ot->modal = node_resize_modal;
1144 ot->cancel = node_resize_cancel;
1145
1146 /* flags */
1147 ot->flag = OPTYPE_BLOCKING;
1148}
1149
1151
1152/* -------------------------------------------------------------------- */
1155
1157{
1158 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1159 if (sock->flag & SOCK_HIDDEN) {
1160 return true;
1161 }
1162 }
1163 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
1164 if (sock->flag & SOCK_HIDDEN) {
1165 return true;
1166 }
1167 }
1168 return false;
1169}
1170
1171void node_set_hidden_sockets(bNode *node, int set)
1172{
1173 /* The Reroute node is the socket itself, do not hide this. */
1174 if (node->is_reroute()) {
1175 return;
1176 }
1177
1178 if (set == 0) {
1179 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1180 sock->flag &= ~SOCK_HIDDEN;
1181 }
1182 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
1183 sock->flag &= ~SOCK_HIDDEN;
1184 }
1185 }
1186 else {
1187 /* Hide unused sockets. */
1188 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1189 if (sock->link == nullptr) {
1190 sock->flag |= SOCK_HIDDEN;
1191 }
1192 }
1193 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
1194 if ((sock->flag & SOCK_IS_LINKED) == 0) {
1195 sock->flag |= SOCK_HIDDEN;
1196 }
1197 }
1198 }
1199}
1200
1201bool node_is_previewable(const SpaceNode &snode, const bNodeTree &ntree, const bNode &node)
1202{
1203 if (!(snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS) ||
1205 {
1206 return false;
1207 }
1208 if (ntree.type == NTREE_SHADER) {
1209 return USER_EXPERIMENTAL_TEST(&U, use_shader_node_previews) && !node.is_frame() &&
1211 }
1212 return node.typeinfo->flag & NODE_PREVIEW;
1213}
1214
1215static bool cursor_isect_multi_input_socket(const float2 &cursor, const bNodeSocket &socket)
1216{
1217 const float node_socket_height = node_socket_calculate_height(socket);
1218 const float2 location = socket.runtime->location;
1219 /* `.xmax = socket->location[0] + NODE_SOCKSIZE * 5.5f`
1220 * would be the same behavior as for regular sockets.
1221 * But keep it smaller because for multi-input socket you
1222 * sometimes want to drag the link to the other side, if you may
1223 * accidentally pick the wrong link otherwise. */
1224 rctf multi_socket_rect;
1225 BLI_rctf_init(&multi_socket_rect,
1226 location.x - NODE_SOCKSIZE * 4.0f,
1227 location.x + NODE_SOCKSIZE * 2.0f,
1228 location.y - node_socket_height,
1229 location.y + node_socket_height);
1230 if (BLI_rctf_isect_pt(&multi_socket_rect, cursor.x, cursor.y)) {
1231 return true;
1232 }
1233 return false;
1234}
1235
1237 ARegion &region,
1238 const float2 &cursor,
1239 const eNodeSocketInOut in_out)
1240{
1241 const float view2d_scale = UI_view2d_scale_get_x(&region.v2d);
1242 const float max_distance = NODE_SOCKSIZE + std::clamp(20.0f / view2d_scale, 5.0f, 30.0f);
1243 const float padded_socket_size = NODE_SOCKSIZE + 4;
1244
1245 bNodeTree &tree = *snode.edittree;
1246 tree.ensure_topology_cache();
1247
1249 if (sorted_nodes.is_empty()) {
1250 return nullptr;
1251 }
1252
1253 float best_distance = FLT_MAX;
1254 bNodeSocket *best_socket = nullptr;
1255
1256 auto update_best_socket = [&](bNodeSocket *socket, const float distance) {
1257 if (socket_is_occluded(socket->runtime->location, socket->owner_node(), sorted_nodes)) {
1258 return;
1259 }
1260 if (distance < best_distance) {
1261 best_distance = distance;
1262 best_socket = socket;
1263 }
1264 };
1265
1266 for (bNode *node : sorted_nodes) {
1267 const bool node_collapsed = node->flag & NODE_COLLAPSED;
1268 if (!node->is_reroute() && !node_collapsed &&
1269 node->runtime->draw_bounds.ymax - cursor.y < NODE_DY)
1270 {
1271 /* Don't pick socket when cursor is over node header. This allows the user to always resize
1272 * by dragging on the left and right side of the header. */
1273 continue;
1274 }
1275 if (in_out & SOCK_IN) {
1276 for (bNodeSocket *sock : node->input_sockets()) {
1277 if (!sock->is_icon_visible()) {
1278 continue;
1279 }
1280 const float2 location = sock->runtime->location;
1281 const float distance = math::distance(location, cursor);
1282 if (sock->flag & SOCK_MULTI_INPUT && !node_collapsed) {
1283 if (cursor_isect_multi_input_socket(cursor, *sock)) {
1284 update_best_socket(sock, distance);
1285 continue;
1286 }
1287 }
1288 if (distance < max_distance) {
1289 update_best_socket(sock, distance);
1290 }
1291 }
1292 }
1293 if (in_out & SOCK_OUT) {
1294 for (bNodeSocket *sock : node->output_sockets()) {
1295 if (!sock->is_icon_visible()) {
1296 continue;
1297 }
1298 const float2 location = sock->runtime->location;
1299 const float distance = math::distance(location, cursor);
1300 if (distance < max_distance) {
1301 if (node_collapsed) {
1302 if (location.x - cursor.x > padded_socket_size) {
1303 /* Needed to be able to resize collapsed nodes. */
1304 continue;
1305 }
1306 }
1307 update_best_socket(sock, distance);
1308 }
1309 }
1310 }
1311 }
1312
1313 return best_socket;
1314}
1315
1317
1318/* -------------------------------------------------------------------- */
1321
1322float node_link_dim_factor(const View2D &v2d, const bNodeLink &link)
1323{
1324 if (link.fromsock == nullptr || link.tosock == nullptr) {
1325 return 1.0f;
1326 }
1328 return 0.2f;
1329 }
1330
1331 const float2 from = link.fromsock->runtime->location;
1332 const float2 to = link.tosock->runtime->location;
1333
1334 const float min_endpoint_distance = std::min(
1335 std::max(BLI_rctf_length_x(&v2d.cur, from.x), BLI_rctf_length_y(&v2d.cur, from.y)),
1336 std::max(BLI_rctf_length_x(&v2d.cur, to.x), BLI_rctf_length_y(&v2d.cur, to.y)));
1337
1338 if (min_endpoint_distance == 0.0f) {
1339 return 1.0f;
1340 }
1341 const float viewport_width = BLI_rctf_size_x(&v2d.cur);
1342 return std::clamp(1.0f - min_endpoint_distance / viewport_width * 10.0f, 0.05f, 1.0f);
1343}
1344
1346{
1347 return bke::node_link_is_hidden(link) || node_link_dim_factor(v2d, link) < 0.5f;
1348}
1349
1351
1352/* -------------------------------------------------------------------- */
1355
1357 const Map<bNode *, bNode *> &node_map,
1358 bNode *node)
1359{
1360 bNode *parent;
1361
1362 node->flag |= NODE_TEST;
1363
1364 /* Find first selected parent. */
1365 for (parent = node->parent; parent; parent = parent->parent) {
1366 if (parent->flag & SELECT) {
1367 if (!(parent->flag & NODE_TEST)) {
1368 node_duplicate_reparent_recursive(ntree, node_map, parent);
1369 }
1370 break;
1371 }
1372 }
1373 /* Reparent node copy to parent copy. */
1374 if (parent) {
1375 bke::node_detach_node(*ntree, *node_map.lookup(node));
1376 bke::node_attach_node(*ntree, *node_map.lookup(node), *node_map.lookup(parent));
1377 }
1378}
1379
1381{
1382 /* We don't have the old tree for looking up output nodes by ID,
1383 * so we have to build a map first to find copied output nodes in the new tree. */
1384 Map<int32_t, bNode *> dst_output_node_map;
1385 for (const auto &item : node_map.items()) {
1386 if (bke::all_zone_output_node_types().contains(item.key->type_legacy)) {
1387 dst_output_node_map.add_new(item.key->identifier, item.value);
1388 }
1389 }
1390
1391 for (bNode *dst_node : node_map.values()) {
1392 if (bke::all_zone_input_node_types().contains(dst_node->type_legacy)) {
1393 const bke::bNodeZoneType &zone_type = *bke::zone_type_by_node_type(dst_node->type_legacy);
1394 int &output_node_id = zone_type.get_corresponding_output_id(*dst_node);
1395 if (const bNode *output_node = dst_output_node_map.lookup_default(output_node_id, nullptr)) {
1396 output_node_id = output_node->identifier;
1397 }
1398 else {
1399 output_node_id = 0;
1401 }
1402 }
1403 }
1404}
1405
1407{
1408 Main *bmain = CTX_data_main(C);
1409 SpaceNode *snode = CTX_wm_space_node(C);
1410 bNodeTree *ntree = snode->edittree;
1411 const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
1412 bool linked = RNA_boolean_get(op->ptr, "linked") || ((U.dupflag & USER_DUP_NTREE) == 0);
1413 const bool dupli_node_tree = !linked;
1414
1416
1417 Map<bNode *, bNode *> node_map;
1419 Map<const ID *, ID *> duplicated_node_groups;
1420
1421 node_select_paired(*ntree);
1422
1423 for (bNode *node : get_selected_nodes(*ntree)) {
1425 ntree, *node, LIB_ID_COPY_DEFAULT, std::nullopt, std::nullopt, socket_map);
1426 node_map.add_new(node, new_node);
1427
1428 if (node->id && dupli_node_tree && !ID_IS_LINKED(node->id)) {
1429 ID *new_group = duplicated_node_groups.lookup_or_add_cb(node->id, [&]() {
1430 ID *new_group = BKE_id_copy(bmain, node->id);
1431 /* Remove user added by copying. */
1432 id_us_min(new_group);
1433 return new_group;
1434 });
1435 id_us_plus(new_group);
1436 id_us_min(new_node->id);
1437 new_node->id = new_group;
1438 }
1439 }
1440
1441 if (node_map.is_empty()) {
1442 return OPERATOR_CANCELLED;
1443 }
1444
1445 /* Copy links between selected nodes. */
1446 bNodeLink *lastlink = (bNodeLink *)ntree->links.last;
1447 LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
1448 /* This creates new links between copied nodes. If keep_inputs is set, also copies input links
1449 * from unselected (when fromnode is null)! */
1450 if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
1451 (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT))))
1452 {
1453 bNodeLink *newlink = MEM_callocN<bNodeLink>("bNodeLink");
1454 newlink->flag = link->flag;
1455 newlink->tonode = node_map.lookup(link->tonode);
1456 newlink->tosock = socket_map.lookup(link->tosock);
1457
1458 if (link->tosock->flag & SOCK_MULTI_INPUT) {
1459 newlink->multi_input_sort_id = link->multi_input_sort_id;
1460 }
1461
1462 if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
1463 newlink->fromnode = node_map.lookup(link->fromnode);
1464 newlink->fromsock = socket_map.lookup(link->fromsock);
1465 }
1466 else {
1467 /* Input node not copied, this keeps the original input linked. */
1468 newlink->fromnode = link->fromnode;
1469 newlink->fromsock = link->fromsock;
1470 }
1471
1472 BLI_addtail(&ntree->links, newlink);
1473 }
1474
1475 /* Make sure we don't copy new links again. */
1476 if (link == lastlink) {
1477 break;
1478 }
1479 }
1480
1481 for (bNode *node : node_map.values()) {
1483 }
1484
1485 ntree->ensure_topology_cache();
1486 for (bNode *node : node_map.values()) {
1488 }
1489
1490 /* Clear flags for recursive depth-first iteration. */
1491 for (bNode *node : ntree->all_nodes()) {
1492 node->flag &= ~NODE_TEST;
1493 }
1494 /* Reparent copied nodes. */
1495 for (bNode *node : node_map.keys()) {
1496 if (!(node->flag & NODE_TEST)) {
1497 node_duplicate_reparent_recursive(ntree, node_map, node);
1498 }
1499 }
1500
1501 {
1502 /* Use temporary map that has const key, because that's what the function below expects. */
1503 Map<const bNode *, bNode *> const_node_map;
1504 for (const auto item : node_map.items()) {
1505 const_node_map.add(item.key, item.value);
1506 }
1507 remap_node_pairing(*ntree, const_node_map);
1508 }
1509
1510 /* Deselect old nodes, select the copies instead. */
1511 for (const auto item : node_map.items()) {
1512 bNode *src_node = item.key;
1513 bNode *dst_node = item.value;
1514
1515 bke::node_set_selected(*src_node, false);
1516 src_node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
1517 bke::node_set_selected(*dst_node, true);
1518 }
1519
1521 BKE_main_ensure_invariants(*bmain, snode->edittree->id);
1522 return OPERATOR_FINISHED;
1523}
1524
1526{
1527 PropertyRNA *prop;
1528
1529 /* identifiers */
1530 ot->name = "Duplicate Nodes";
1531 ot->description = "Duplicate selected nodes";
1532 ot->idname = "NODE_OT_duplicate";
1533
1534 /* API callbacks. */
1535 ot->exec = node_duplicate_exec;
1537
1538 /* flags */
1539 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1540
1542 ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes");
1543
1544 prop = RNA_def_boolean(ot->srna,
1545 "linked",
1546 true,
1547 "Linked",
1548 "Duplicate node but not node trees, linking to the original data");
1550}
1551
1552/* Goes over all scenes, reads render layers. */
1554{
1555 Main *bmain = CTX_data_main(C);
1556 SpaceNode *snode = CTX_wm_space_node(C);
1557 Scene *curscene = CTX_data_scene(C);
1558 bNodeTree &edit_tree = *snode->edittree;
1559
1561
1562 /* first tag scenes unread */
1563 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1564 scene->id.tag |= ID_TAG_DOIT;
1565 }
1566
1567 for (bNode *node : edit_tree.all_nodes()) {
1568 if ((node->type_legacy == CMP_NODE_R_LAYERS) ||
1569 (node->type_legacy == CMP_NODE_CRYPTOMATTE &&
1570 node->custom1 == CMP_NODE_CRYPTOMATTE_SOURCE_RENDER))
1571 {
1572 ID *id = node->id;
1573 if (id == nullptr) {
1574 continue;
1575 }
1576 if (id->tag & ID_TAG_DOIT) {
1577 RE_ReadRenderResult(curscene, (Scene *)id);
1579 id->tag &= ~ID_TAG_DOIT;
1580 }
1581 }
1582 }
1583
1584 BKE_main_ensure_invariants(*bmain, edit_tree.id);
1585
1586 return OPERATOR_FINISHED;
1587}
1588
1590{
1591 ot->name = "Read View Layers";
1592 ot->idname = "NODE_OT_read_viewlayers";
1593 ot->description = "Read all render layers of all used scenes";
1594
1596
1597 ot->poll = composite_node_active;
1598}
1599
1601{
1602 Scene *sce = CTX_data_scene(C);
1603
1604 /* This is actually a test whether scene is used by the compositor or not.
1605 * All the nodes are using same render result, so there is no need to do
1606 * anything smart about check how exactly scene is used. */
1607 bNode *node = nullptr;
1608 for (bNode *node_iter : sce->compositing_node_group->all_nodes()) {
1609 if (node_iter->id == (ID *)sce) {
1610 node = node_iter;
1611 break;
1612 }
1613 }
1614
1615 if (node) {
1616 ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&sce->view_layers, node->custom1);
1617
1618 if (view_layer) {
1619 PointerRNA op_ptr;
1620
1621 WM_operator_properties_create(&op_ptr, "RENDER_OT_render");
1622 RNA_string_set(&op_ptr, "layer", view_layer->name);
1623 RNA_string_set(&op_ptr, "scene", sce->id.name + 2);
1624
1625 /* To keep keyframe positions. */
1626 sce->r.scemode |= R_NO_FRAME_UPDATE;
1627
1629 C, "RENDER_OT_render", wm::OpCallContext::InvokeDefault, &op_ptr, nullptr);
1630
1632
1633 return OPERATOR_FINISHED;
1634 }
1635 }
1636 return OPERATOR_CANCELLED;
1637}
1638
1640{
1641 ot->name = "Render Changed Layer";
1642 ot->idname = "NODE_OT_render_changed";
1643 ot->description = "Render current scene, when input node's layer has been changed";
1644
1646
1647 ot->poll = composite_node_active;
1648
1649 /* flags */
1650 ot->flag = 0;
1651}
1652
1654
1655/* -------------------------------------------------------------------- */
1658
1664static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag, const bool tag_update = false)
1665{
1666 int tot_eq = 0, tot_neq = 0;
1667
1668 for (bNode *node : snode->edittree->all_nodes()) {
1669 if (node->flag & SELECT) {
1670
1671 if (toggle_flag == NODE_PREVIEW && !node_is_previewable(*snode, *snode->edittree, *node)) {
1672 continue;
1673 }
1674 if (toggle_flag == NODE_OPTIONS &&
1675 !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
1676 {
1677 continue;
1678 }
1679
1680 if (node->flag & toggle_flag) {
1681 tot_eq++;
1682 }
1683 else {
1684 tot_neq++;
1685 }
1686 }
1687 }
1688 for (bNode *node : snode->edittree->all_nodes()) {
1689 if (node->flag & SELECT) {
1690
1691 if (toggle_flag == NODE_PREVIEW && !node_is_previewable(*snode, *snode->edittree, *node)) {
1692 continue;
1693 }
1694 if (toggle_flag == NODE_OPTIONS &&
1695 !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
1696 {
1697 continue;
1698 }
1699
1700 if ((tot_eq && tot_neq) || tot_eq == 0) {
1701 node->flag |= toggle_flag;
1702 }
1703 else {
1704 node->flag &= ~toggle_flag;
1705 }
1706
1707 if (tag_update) {
1709 }
1710 }
1711 }
1712}
1713
1715{
1716 SpaceNode *snode = CTX_wm_space_node(C);
1717
1718 /* Sanity checking (poll callback checks this already). */
1719 if ((snode == nullptr) || (snode->edittree == nullptr)) {
1720 return OPERATOR_CANCELLED;
1721 }
1722
1724
1726
1727 return OPERATOR_FINISHED;
1728}
1729
1731{
1732 /* identifiers */
1733 ot->name = "Collapse";
1734 ot->description = "Toggle collapsing of selected nodes";
1735 ot->idname = "NODE_OT_hide_toggle";
1736
1737 /* callbacks */
1740
1741 /* flags */
1742 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1743}
1744
1746{
1747 SpaceNode *snode = CTX_wm_space_node(C);
1748
1749 /* Sanity checking (poll callback checks this already). */
1750 if ((snode == nullptr) || (snode->edittree == nullptr)) {
1751 return OPERATOR_CANCELLED;
1752 }
1753
1754 node_flag_toggle_exec(snode, NODE_PREVIEW, true);
1755
1758
1760
1761 return OPERATOR_FINISHED;
1762}
1763
1765{
1767 SpaceNode *snode = CTX_wm_space_node(C);
1768 if (ED_node_supports_preview(snode)) {
1769 return true;
1770 }
1771 }
1772 return false;
1773}
1774
1776{
1777 /* identifiers */
1778 ot->name = "Toggle Node Preview";
1779 ot->description = "Toggle preview display for selected nodes";
1780 ot->idname = "NODE_OT_preview_toggle";
1781
1782 /* callbacks */
1784 ot->poll = node_previewable;
1785
1786 /* flags */
1787 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1788}
1789
1791{
1792 SpaceNode *snode = CTX_wm_space_node(C);
1794 Main *bmain = CTX_data_main(C);
1795 bNodeTree *ntree = nullptr;
1796 bNode *node = nullptr;
1797
1798 if (ptr.data) {
1799 node = static_cast<bNode *>(ptr.data);
1800 ntree = reinterpret_cast<bNodeTree *>(ptr.owner_id);
1801 }
1802 else if (snode && snode->edittree) {
1803 ntree = snode->edittree;
1804 node = bke::node_get_active(*ntree);
1805 }
1806
1807 if (!node) {
1808 return OPERATOR_CANCELLED;
1809 }
1810
1811 if (node->is_type("CompositorNodeViewer")) {
1812 for (bNode *other_node : ntree->all_nodes()) {
1813 if (other_node->type_legacy == node->type_legacy) {
1814 other_node->flag &= ~NODE_DO_OUTPUT;
1815 }
1816 node->flag |= NODE_DO_OUTPUT;
1817
1820 }
1821 }
1822 else if (node->is_type("GeometryNodeViewer")) {
1823 /* Geometry nodes viewers don't rely on NODE_DO_OUTPUT flag alone. */
1824 viewer_path::activate_geometry_node(*bmain, *snode, *node);
1825 }
1826 else {
1827 return OPERATOR_CANCELLED;
1828 }
1829
1831 BKE_main_ensure_invariants(*bmain, snode->edittree->id);
1832 return OPERATOR_FINISHED;
1833}
1834
1836{
1837 ot->name = "Activate Viewer Node";
1838 ot->description = "Activate selected viewer node in compositor and geometry nodes";
1839 ot->idname = "NODE_OT_activate_viewer";
1840
1843
1844 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1845}
1846
1848{
1849 SpaceNode &snode = *CTX_wm_space_node(C);
1850 bNodeTree &ntree = *snode.edittree;
1851 Main &bmain = *CTX_data_main(C);
1852
1854 &bmain, (StringRef(ntree.id.name) + " Inlined").c_str(), ntree.idname);
1855
1857 params.allow_preserving_repeat_zones = false;
1858 nodes::inline_shader_node_tree(ntree, *new_tree, params);
1859 bNode *group_node = bke::node_add_node(C, ntree, ntree.typeinfo->group_idname);
1860 group_node->id = &new_tree->id;
1861 node_deselect_all(ntree);
1862 bke::node_set_selected(*group_node, true);
1863 bke::node_set_active(ntree, *group_node);
1864
1866
1867 return OPERATOR_FINISHED;
1868}
1869
1871{
1872 ot->name = "Test Inlining Shader Nodes";
1873 ot->description = "Create a new inlined shader node tree as is consumed by renderers";
1874 ot->idname = "NODE_OT_test_inlining_shader_nodes";
1875
1878
1879 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1880}
1881
1883{
1884 SpaceNode &snode = *CTX_wm_space_node(C);
1885 WorkSpace &workspace = *CTX_wm_workspace(C);
1886
1887 bNode *active_viewer = viewer_path::find_geometry_nodes_viewer(workspace.viewer_path, snode);
1888
1889 for (bNode *node : snode.edittree->all_nodes()) {
1890 if (node->type_legacy != GEO_NODE_VIEWER) {
1891 continue;
1892 }
1893 if (node == active_viewer) {
1894 node->flag &= ~NODE_DO_OUTPUT;
1896 /* At most, only one viewer is active so break early. */
1897 break;
1898 }
1899 }
1900
1902
1903 return OPERATOR_FINISHED;
1904}
1905
1907{
1908 /* identifiers */
1909 ot->name = "Deactivate Viewer Node";
1910 ot->description = "Deactivate selected viewer node in geometry nodes";
1911 ot->idname = __func__;
1912
1913 /* callbacks */
1916
1917 /* flags */
1918 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1919}
1920
1922{
1923 SpaceNode *snode = CTX_wm_space_node(C);
1924 WorkSpace *workspace = CTX_wm_workspace(C);
1926 bNode *node = nullptr;
1927 bNodeTree *ntree = nullptr;
1929
1930 if (ptr.data) {
1931 node = static_cast<bNode *>(ptr.data);
1932 ntree = reinterpret_cast<bNodeTree *>(ptr.owner_id);
1933 }
1934 else if (snode && snode->edittree) {
1935 ntree = snode->edittree;
1936 node = bke::node_get_active(*ntree);
1937 }
1938
1939 if (!node) {
1940 return OPERATOR_CANCELLED;
1941 }
1942
1943 bNode *active_viewer = viewer_path::find_geometry_nodes_viewer(workspace->viewer_path, *snode);
1944 if (node == active_viewer) {
1946 C, "NODE_OT_deactivate_viewer", wm::OpCallContext::InvokeDefault, nullptr, nullptr);
1947 }
1948 else {
1950 C, "NODE_OT_activate_viewer", wm::OpCallContext::InvokeDefault, nullptr, nullptr);
1951 }
1952
1953 return ret;
1954}
1955
1957{
1958 ot->name = "Toggle Viewer Node";
1959 ot->description = "Toggle selected viewer node in compositor and geometry nodes";
1960 ot->idname = "NODE_OT_toggle_viewer";
1961
1964
1965 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1966}
1967
1969{
1970 SpaceNode *snode = CTX_wm_space_node(C);
1971
1972 /* Sanity checking (poll callback checks this already). */
1973 if ((snode == nullptr) || (snode->edittree == nullptr)) {
1974 return OPERATOR_CANCELLED;
1975 }
1976
1978
1980
1981 return OPERATOR_FINISHED;
1982}
1983
1985{
1986 /* identifiers */
1987 ot->name = "Toggle Node Options";
1988 ot->description = "Toggle option buttons display for selected nodes";
1989 ot->idname = "NODE_OT_options_toggle";
1990
1991 /* callbacks */
1994
1995 /* flags */
1996 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1997}
1998
2000{
2001 SpaceNode *snode = CTX_wm_space_node(C);
2002
2003 /* Sanity checking (poll callback checks this already). */
2004 if ((snode == nullptr) || (snode->edittree == nullptr)) {
2005 return OPERATOR_CANCELLED;
2006 }
2007
2009
2010 /* Toggle for all selected nodes */
2011 bool hidden = false;
2012 for (bNode *node : snode->edittree->all_nodes()) {
2013 if (node->flag & SELECT) {
2014 if (node_has_hidden_sockets(node)) {
2015 hidden = true;
2016 break;
2017 }
2018 }
2019 }
2020
2021 for (bNode *node : snode->edittree->all_nodes()) {
2022 if (node->flag & SELECT) {
2023 node_set_hidden_sockets(node, !hidden);
2024 }
2025 }
2026
2028
2030 /* Hack to force update of the button state after drawing, see #112462. */
2032
2033 return OPERATOR_FINISHED;
2034}
2035
2037{
2038 /* identifiers */
2039 ot->name = "Toggle Hidden Node Sockets";
2040 ot->description = "Toggle unused node socket display";
2041 ot->idname = "NODE_OT_hide_socket_toggle";
2042
2043 /* callbacks */
2046
2047 /* flags */
2048 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2049}
2050
2052
2053/* -------------------------------------------------------------------- */
2056
2058{
2059 Main *bmain = CTX_data_main(C);
2060 SpaceNode *snode = CTX_wm_space_node(C);
2061
2063
2064 for (bNode *node : snode->edittree->all_nodes()) {
2065 if ((node->flag & SELECT) && !node->typeinfo->no_muting) {
2066 node->flag ^= NODE_MUTED;
2068 }
2069 }
2070
2071 BKE_main_ensure_invariants(*bmain, snode->edittree->id);
2072
2073 return OPERATOR_FINISHED;
2074}
2075
2077{
2078 /* identifiers */
2079 ot->name = "Toggle Node Mute";
2080 ot->description = "Toggle muting of selected nodes";
2081 ot->idname = "NODE_OT_mute_toggle";
2082
2083 /* callbacks */
2084 ot->exec = node_mute_exec;
2086
2087 /* flags */
2088 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2089}
2090
2092
2093/* -------------------------------------------------------------------- */
2096
2098{
2099 Main *bmain = CTX_data_main(C);
2100 SpaceNode *snode = CTX_wm_space_node(C);
2101
2103
2104 /* Delete paired nodes as well. */
2106
2107 LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
2108 if (node->flag & SELECT) {
2109 bke::node_remove_node(bmain, *snode->edittree, *node, true);
2110 }
2111 }
2112
2114 BKE_main_ensure_invariants(*bmain, snode->edittree->id);
2115
2116 return OPERATOR_FINISHED;
2117}
2118
2120{
2121 /* identifiers */
2122 ot->name = "Delete";
2123 ot->description = "Remove selected nodes";
2124 ot->idname = "NODE_OT_delete";
2125
2126 /* API callbacks. */
2127 ot->exec = node_delete_exec;
2129
2130 /* flags */
2131 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2132}
2133
2135
2136/* -------------------------------------------------------------------- */
2139
2141{
2142 Main *bmain = CTX_data_main(C);
2143 SpaceNode *snode = CTX_wm_space_node(C);
2144
2146
2147 /* Delete paired nodes as well. */
2149
2150 LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
2151 if (node->flag & SELECT) {
2153 bke::node_remove_node(bmain, *snode->edittree, *node, true);
2154
2155 /* Since this node might have been animated, and that animation data been
2156 * deleted, a notifier call is necessary to redraw any animation editor. */
2158 }
2159 }
2160
2161 BKE_main_ensure_invariants(*bmain, snode->edittree->id);
2162
2163 return OPERATOR_FINISHED;
2164}
2165
2167{
2168 /* identifiers */
2169 ot->name = "Delete with Reconnect";
2170 ot->description = "Remove nodes and reconnect nodes as if deletion was muted";
2171 ot->idname = "NODE_OT_delete_reconnect";
2172
2173 /* API callbacks. */
2176
2177 /* flags */
2178 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2179}
2180
2182
2183/* -------------------------------------------------------------------- */
2186
2188{
2189 SpaceNode &snode = *CTX_wm_space_node(C);
2190 bNodeTree &ntree = *snode.edittree;
2191
2192 bNode *active_node = bke::node_get_active(ntree);
2193 if (!active_node) {
2194 return OPERATOR_CANCELLED;
2195 }
2196
2197 for (bNode *node : ntree.all_nodes()) {
2198 if (node->flag & NODE_SELECT && node != active_node) {
2199 if (active_node->flag & NODE_CUSTOM_COLOR) {
2200 node->flag |= NODE_CUSTOM_COLOR;
2201 copy_v3_v3(node->color, active_node->color);
2202 }
2203 else {
2204 node->flag &= ~NODE_CUSTOM_COLOR;
2205 }
2206 }
2207 }
2208
2210
2211 return OPERATOR_FINISHED;
2212}
2213
2215{
2216 /* identifiers */
2217 ot->name = "Copy Color";
2218 ot->description = "Copy color to all selected nodes";
2219 ot->idname = "NODE_OT_node_copy_color";
2220
2221 /* API callbacks. */
2222 ot->exec = node_copy_color_exec;
2224
2225 /* flags */
2226 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2227}
2228
2230
2231/* -------------------------------------------------------------------- */
2234
2236{
2238 SpaceNode *snode = CTX_wm_space_node(C);
2239
2240 /* Test if we have a render engine that supports shaders scripts. */
2241 if (!(type && type->update_script_node)) {
2242 return false;
2243 }
2244
2245 /* See if we have a shader script node in context. */
2246 bNode *node = (bNode *)CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data;
2247
2248 if (!node && snode && snode->edittree) {
2249 node = bke::node_get_active(*snode->edittree);
2250 }
2251
2252 if (node && node->type_legacy == SH_NODE_SCRIPT) {
2254
2255 if (node->id || nss->filepath[0]) {
2257 }
2258 }
2259
2260 return false;
2261}
2262
2264{
2266 SpaceNode *snode = CTX_wm_space_node(C);
2267 PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript);
2268
2269 /* setup render engine */
2270 RenderEngine *engine = RE_engine_create(type);
2271 engine->reports = op->reports;
2272
2273 bNodeTree *ntree_base = nullptr;
2274 bNode *node = nullptr;
2275 if (nodeptr.data) {
2276 ntree_base = (bNodeTree *)nodeptr.owner_id;
2277 node = (bNode *)nodeptr.data;
2278 }
2279 else if (snode && snode->edittree) {
2280 ntree_base = snode->edittree;
2281 node = bke::node_get_active(*snode->edittree);
2282 }
2283
2284 /* Update node. */
2285 type->update_script_node(engine, ntree_base, node);
2286
2287 RE_engine_free(engine);
2288
2289 return OPERATOR_FINISHED;
2290}
2291
2293{
2294 /* identifiers */
2295 ot->name = "Script Node Update";
2296 ot->description = "Update shader script node with new sockets and options from the script";
2297 ot->idname = "NODE_OT_shader_script_update";
2298
2299 /* API callbacks. */
2302
2303 /* flags */
2304 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2305}
2306
2308
2309/* -------------------------------------------------------------------- */
2312
2314 ARegion *region,
2315 int x,
2316 int y,
2317 int backdrop_width,
2318 int backdrop_height,
2319 float *fx,
2320 float *fy)
2321{
2322 float bufx = backdrop_width * snode->zoom;
2323 float bufy = backdrop_height * snode->zoom;
2324
2325 *fx = (bufx > 0.0f ? (float(x) - 0.5f * region->winx - snode->xof) / bufx + 0.5f : 0.0f);
2326 *fy = (bufy > 0.0f ? (float(y) - 0.5f * region->winy - snode->yof) / bufy + 0.5f : 0.0f);
2327}
2328
2330{
2331 Main *bmain = CTX_data_main(C);
2332 void *lock;
2333
2335
2336 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
2337 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
2338
2339 if (ibuf) {
2340 ARegion *region = CTX_wm_region(C);
2341 SpaceNode *snode = CTX_wm_space_node(C);
2342 bNodeTree *btree = snode->nodetree;
2343 rcti rect;
2344 rctf rectf;
2345
2346 /* Get border from operator. */
2348
2349 /* Convert border to unified space within backdrop image. */
2351 snode, region, rect.xmin, rect.ymin, ibuf->x, ibuf->y, &rectf.xmin, &rectf.ymin);
2352
2354 snode, region, rect.xmax, rect.ymax, ibuf->x, ibuf->y, &rectf.xmax, &rectf.ymax);
2355
2356 /* Clamp coordinates. */
2357 rectf.xmin = max_ff(rectf.xmin, 0.0f);
2358 rectf.ymin = max_ff(rectf.ymin, 0.0f);
2359 rectf.xmax = min_ff(rectf.xmax, 1.0f);
2360 rectf.ymax = min_ff(rectf.ymax, 1.0f);
2361
2362 if (rectf.xmin < rectf.xmax && rectf.ymin < rectf.ymax) {
2363 btree->viewer_border = rectf;
2364
2365 if (rectf.xmin == 0.0f && rectf.ymin == 0.0f && rectf.xmax == 1.0f && rectf.ymax == 1.0f) {
2366 btree->flag &= ~NTREE_VIEWER_BORDER;
2367 }
2368 else {
2369 btree->flag |= NTREE_VIEWER_BORDER;
2370 }
2371
2372 BKE_main_ensure_invariants(*bmain, btree->id);
2374 }
2375 else {
2376 btree->flag &= ~NTREE_VIEWER_BORDER;
2377 }
2378 }
2379
2380 BKE_image_release_ibuf(ima, ibuf, lock);
2381
2382 return OPERATOR_FINISHED;
2383}
2384
2386{
2387 /* identifiers */
2388 ot->name = "Viewer Region";
2389 ot->description = "Set the boundaries for viewer operations";
2390 ot->idname = "NODE_OT_viewer_border";
2391
2392 /* API callbacks. */
2393 ot->invoke = WM_gesture_box_invoke;
2394 ot->exec = viewer_border_exec;
2395 ot->modal = WM_gesture_box_modal;
2396 ot->cancel = WM_gesture_box_cancel;
2397 ot->poll = composite_node_active;
2398
2399 /* flags */
2400 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2401
2402 /* properties */
2404}
2405
2407{
2408 SpaceNode *snode = CTX_wm_space_node(C);
2409 bNodeTree *btree = snode->nodetree;
2410
2411 btree->flag &= ~NTREE_VIEWER_BORDER;
2414
2415 return OPERATOR_FINISHED;
2416}
2417
2419{
2420 /* identifiers */
2421 ot->name = "Clear Viewer Region";
2422 ot->description = "Clear the boundaries for viewer operations";
2423 ot->idname = "NODE_OT_clear_viewer_border";
2424
2425 /* API callbacks. */
2427 ot->poll = composite_node_active;
2428
2429 /* flags */
2430 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2431}
2432
2434
2435/* -------------------------------------------------------------------- */
2438
2440{
2441 SpaceNode *snode = CTX_wm_space_node(C);
2443 bNodeTree *ntree = nullptr;
2444 bNode *node = nullptr;
2445
2446 if (ptr.data) {
2447 node = (bNode *)ptr.data;
2448 ntree = (bNodeTree *)ptr.owner_id;
2449 }
2450 else if (snode && snode->edittree) {
2451 ntree = snode->edittree;
2452 node = bke::node_get_active(*snode->edittree);
2453 }
2454
2455 if (!node || node->type_legacy != CMP_NODE_CRYPTOMATTE_LEGACY) {
2456 return OPERATOR_CANCELLED;
2457 }
2458
2460
2462
2463 return OPERATOR_FINISHED;
2464}
2465
2467{
2468 /* identifiers */
2469 ot->name = "Add Cryptomatte Socket";
2470 ot->description = "Add a new input layer to a Cryptomatte node";
2471 ot->idname = "NODE_OT_cryptomatte_layer_add";
2472
2473 /* callbacks */
2476
2477 /* flags */
2478 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2479}
2480
2482
2483/* -------------------------------------------------------------------- */
2486
2488{
2489 SpaceNode *snode = CTX_wm_space_node(C);
2491 bNodeTree *ntree = nullptr;
2492 bNode *node = nullptr;
2493
2494 if (ptr.data) {
2495 node = (bNode *)ptr.data;
2496 ntree = (bNodeTree *)ptr.owner_id;
2497 }
2498 else if (snode && snode->edittree) {
2499 ntree = snode->edittree;
2500 node = bke::node_get_active(*snode->edittree);
2501 }
2502
2503 if (!node || node->type_legacy != CMP_NODE_CRYPTOMATTE_LEGACY) {
2504 return OPERATOR_CANCELLED;
2505 }
2506
2507 if (!ntreeCompositCryptomatteRemoveSocket(ntree, node)) {
2508 return OPERATOR_CANCELLED;
2509 }
2510
2512
2513 return OPERATOR_FINISHED;
2514}
2515
2517{
2518 /* identifiers */
2519 ot->name = "Remove Cryptomatte Socket";
2520 ot->description = "Remove layer from a Cryptomatte node";
2521 ot->idname = "NODE_OT_cryptomatte_layer_remove";
2522
2523 /* callbacks */
2526
2527 /* flags */
2528 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2529}
2530
2532
2533} // namespace blender::ed::space_node
void BKE_callback_exec_id(Main *bmain, ID *id, eCbEvent evt)
Definition callbacks.cc:43
@ 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)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
RenderEngineType * CTX_data_engine_type(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:358
@ LIB_ID_COPY_DEFAULT
void id_us_min(ID *id)
Definition lib_id.cc:366
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
General operations, lookup, etc. for materials.
Material * BKE_material_default_surface()
Material * BKE_material_default_volume()
#define NODE_REROUTE
Definition BKE_node.hh:813
#define NODE_GROUP
Definition BKE_node.hh:811
#define SH_NODE_OUTPUT_WORLD
#define CMP_NODE_VIEWER
#define SH_NODE_EMISSION
#define CMP_NODE_CRYPTOMATTE
#define GEO_NODE_VIEWER
#define TEX_NODE_CHECKER
#define CMP_NODE_CRYPTOMATTE_LEGACY
#define SH_NODE_OUTPUT_MATERIAL
#define SH_NODE_BACKGROUND
#define TEX_NODE_OUTPUT
#define CMP_NODE_R_LAYERS
#define SH_NODE_OUTPUT_LIGHT
#define SH_NODE_OUTPUT_LINESTYLE
#define SH_NODE_SCRIPT
void BKE_ntree_update_tag_active_output_changed(bNodeTree *ntree)
void BKE_ntree_update_after_single_tree_change(Main &bmain, bNodeTree &modified_tree, const NodeTreeUpdateExtraParams &params={})
void BKE_ntree_update_tag_node_mute(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2915
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
Definition scene.cc:2988
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:846
#define BLI_assert(a)
Definition BLI_assert.h:46
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
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.cc:171
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.cc:404
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:202
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b)
Definition rct.cc:193
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size)
Definition rct.cc:458
float BLI_rctf_length_y(const rctf *rect, float y)
Definition rct.cc:182
#define STRNCPY_UTF8(dst, src)
#define CLAMP(a, b, c)
#define ELEM(...)
#define STREQ(a, b)
#define DATA_(msgid)
void COM_execute(Render *render, RenderData *render_data, Scene *scene, bNodeTree *node_tree, const char *view_name, blender::compositor::RenderContext *render_context, blender::compositor::Profiler *profiler, blender::compositor::OutputTypes needed_outputs)
The main method that is used to execute the compositor tree. It can be executed during editing (blenk...
@ DAG_EVAL_RENDER
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:278
void DEG_evaluate_on_refresh(Depsgraph *graph, DepsgraphEvaluateSyncWriteback sync_writeback=DEG_EVALUATE_SYNC_WRITEBACK_NO)
void DEG_graph_replace_owners(Depsgraph *depsgraph, Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition depsgraph.cc:285
void DEG_graph_build_for_compositor_preview(Depsgraph *graph, bNodeTree *nodetree)
void DEG_graph_tag_relations_update(Depsgraph *graph)
void DEG_debug_name_set(Depsgraph *depsgraph, const char *name)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
ViewLayer * DEG_get_input_view_layer(const Depsgraph *graph)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_TAG_DOIT
Definition DNA_ID.h:1036
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
@ ID_IM
@ ID_LA
@ ID_WO
@ ID_MA
@ IMA_SRC_VIEWER
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ CMP_NODE_CRYPTOMATTE_SOURCE_RENDER
@ NTREE_VIEWER_BORDER
@ NODE_TEST
@ NODE_OPTIONS
@ NODE_DO_OUTPUT
@ NODE_ACTIVE
@ NODE_ACTIVE_TEXTURE
@ NODE_CUSTOM_COLOR
@ NODE_COLLAPSED
@ NODE_MUTED
@ NODE_SELECT
@ NODE_PREVIEW
@ NTREE_SHADER
@ NTREE_GEOMETRY
@ NTREE_COMPOSIT
eNodeSocketInOut
@ SOCK_OUT
@ SOCK_IN
@ NODE_LINK_INSERT_TARGET_INVALID
@ SOCK_IS_LINKED
@ SOCK_MULTI_INPUT
@ SOCK_HIDDEN
@ OB_VOLUME
@ SCE_COMPOSITOR_DEVICE_GPU
@ R_MULTIVIEW
@ R_NO_FRAME_UPDATE
@ RGN_TYPE_WINDOW
@ SN_OVERLAY_SHOW_PREVIEWS
@ SN_OVERLAY_SHOW_OVERLAYS
@ SNODE_PIN
@ SNODE_BACKDRAW
@ SPACE_NODE
@ SPACE_IMAGE
@ SNODE_SHADER_OBJECT
#define UI_SCALE_FAC
@ USER_DUP_NTREE
#define USER_EXPERIMENTAL_TEST(userdef, member)
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_space_image_sync(Main *bmain, Image *image, bool ignore_render_viewer)
Definition image_edit.cc:70
Image * ED_space_image(const SpaceImage *sima)
Definition image_edit.cc:40
void ED_node_tree_start(ARegion *region, SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
Definition space_node.cc:78
bool ED_node_is_compositor(const SpaceNode *snode)
Definition node_edit.cc:487
void ED_node_set_active_viewer_key(SpaceNode *snode)
void ED_node_post_apply_transform(bContext *C, bNodeTree *ntree)
Definition node_edit.cc:856
bool ED_node_supports_preview(SpaceNode *snode)
Definition node_edit.cc:507
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:618
bool GPU_is_safe_texture_size(int width, int height)
void GPU_material_free(ListBase *gpumaterial)
Read Guarded memory(de)allocation.
struct blender::bke::bNodeTreeType * ntreeType_Shader
struct blender::bke::bNodeTreeType * ntreeType_Texture
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
#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:1668
float UI_view2d_scale_get_x(const View2D *v2d)
Definition view2d.cc:1921
@ WM_JOB_TYPE_COMPOSITE
Definition WM_api.hh:1777
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1765
@ WM_JOB_PROGRESS
Definition WM_api.hh:1766
#define NC_NODE
Definition WM_types.hh:394
@ KM_RELEASE
Definition WM_types.hh:312
#define NC_ANIMATION
Definition WM_types.hh:388
#define ND_DISPLAY
Definition WM_types.hh:491
#define ND_COMPO_RESULT
Definition WM_types.hh:447
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_NODES
Definition WM_types.hh:436
#define NA_EDITED
Definition WM_types.hh:584
#define NC_MATERIAL
Definition WM_types.hh:380
#define NC_IMAGE
Definition WM_types.hh:384
#define ND_ANIMCHAN
Definition WM_types.hh:496
volatile int lock
#define U
bool is_empty() const
Definition BLI_array.hh:264
ValueIterator values() const &
Definition BLI_map.hh:884
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:620
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
KeyIterator keys() const &
Definition BLI_map.hh:875
bool is_empty() const
Definition BLI_map.hh:986
ItemIterator items() const &
Definition BLI_map.hh:902
virtual const int & get_corresponding_output_id(const bNode &input_bnode) const =0
Map< bNodeInstanceKey, timeit::Nanoseconds > & get_nodes_evaluation_times()
Definition profiler.cc:17
nullptr float
#define SELECT
KDTree_3d * tree
#define GS(x)
#define in
#define out
#define printf(...)
#define output
float distance(VecOp< float, D >, VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
RenderEngine * RE_engine_create(RenderEngineType *type)
void RE_engine_free(RenderEngine *engine)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 fmod(const float2 a, const float b)
#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:3978
bNodeTreeType * node_tree_type_find(StringRef idname)
Definition node.cc:2303
void node_tree_free_tree(bNodeTree &ntree)
Definition node.cc:4455
bNodeTree * node_tree_add_tree_embedded(Main *bmain, ID *owner_id, StringRefNull name, StringRefNull idname)
Definition node.cc:4098
bNodeTree * node_tree_copy_tree(Main *bmain, const bNodeTree &ntree)
Definition node.cc:4114
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
void node_remove_node(Main *bmain, bNodeTree &ntree, bNode &node, bool do_id_user, bool remove_animation=true)
Definition node.cc:4386
bNode * node_add_node(const bContext *C, bNodeTree &ntree, StringRef idname, std::optional< int > unique_identifier=std::nullopt)
Definition node.cc:3477
bNode * node_get_active(bNodeTree &ntree)
Definition node.cc:4685
Span< int > all_zone_output_node_types()
void node_tree_local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
Definition node.cc:4629
bNodeTree * node_tree_localize(bNodeTree *ntree, std::optional< ID * > new_owner_id)
Definition node.cc:4586
void node_internal_relink(bNodeTree &ntree, bNode &node)
Definition node.cc:3908
bool node_set_selected(bNode &node, bool select)
Definition node.cc:4695
bool node_tree_contains_tree(const bNodeTree &tree_to_search_in, const bNodeTree &tree_to_search_for)
Definition node.cc:4663
void node_detach_node(bNodeTree &ntree, bNode &node)
Definition node.cc:3986
bNode * node_add_static_node(const bContext *C, bNodeTree &ntree, int type)
Definition node.cc:3500
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:3810
Span< int > all_zone_input_node_types()
bNodeTree * node_tree_add_tree(Main *bmain, StringRef name, StringRef idname)
Definition node.cc:4085
bNode * node_copy_with_mapping(bNodeTree *dst_tree, const bNode &node_src, int flag, std::optional< StringRefNull > dst_unique_name, std::optional< int > dst_unique_identifier, Map< const bNodeSocket *, bNodeSocket * > &new_socket_map, bool allow_duplicate_names=false)
Definition node.cc:3553
bool node_declaration_ensure(bNodeTree &ntree, bNode &node)
Definition node.cc:4818
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4724
void node_unique_name(bNodeTree &ntree, bNode &node)
Definition node.cc:3453
bool node_link_is_hidden(const bNodeLink &link)
Definition node.cc:3882
void NODE_OT_test_inlining_shader_nodes(wmOperatorType *ot)
void NODE_OT_delete(wmOperatorType *ot)
void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot)
float node_socket_calculate_height(const bNodeSocket &socket)
Definition node_edit.cc:114
void NODE_OT_read_viewlayers(wmOperatorType *ot)
wmKeyMap * node_resize_modal_keymap(wmKeyConfig *keyconf)
Definition node_edit.cc:959
int node_get_resize_cursor(NodeResizeDirection directions)
static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag, const bool tag_update=false)
void tree_draw_order_update(bNodeTree &ntree)
Definition node_draw.cc:316
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:931
static void node_resize_cancel(bContext *C, wmOperator *op)
static wmOperatorStatus node_delete_reconnect_exec(bContext *C, wmOperator *)
static wmOperatorStatus node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *)
static void compo_redrawjob(void *cjv)
Definition node_edit.cc:155
static void compo_statsdrawjob(void *cjv, const char *)
Definition node_edit.cc:147
void NODE_OT_node_copy_color(wmOperatorType *ot)
bool composite_node_editable(bContext *C)
Definition node_edit.cc:454
void NODE_OT_viewer_border(wmOperatorType *ot)
void node_select_paired(bNodeTree &node_tree)
void NODE_OT_activate_viewer(wmOperatorType *ot)
bool node_deselect_all(bNodeTree &node_tree)
static wmOperatorStatus node_activate_viewer_exec(bContext *C, wmOperator *)
bNodeSocket * node_find_indicated_socket(SpaceNode &snode, ARegion &region, const float2 &cursor, const eNodeSocketInOut in_out)
static wmOperatorStatus node_toggle_viewer_exec(bContext *C, wmOperator *)
Array< bNode * > tree_draw_order_calc_nodes_reversed(bNodeTree &ntree)
Definition node_draw.cc:340
void NODE_OT_deactivate_viewer(wmOperatorType *ot)
float2 node_link_calculate_multi_input_position(const float2 &socket_position, const int index, const int total_inputs)
Definition node_edit.cc:124
void NODE_OT_resize(wmOperatorType *ot)
void NODE_OT_render_changed(wmOperatorType *ot)
static wmOperatorStatus node_cryptomatte_add_socket_exec(bContext *C, wmOperator *)
static void compo_updatejob(void *)
Definition node_edit.cc:220
static wmOperatorStatus node_read_viewlayers_exec(bContext *C, wmOperator *)
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:162
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)
static float nearest_node_grid_coord(float co)
Definition node_edit.cc:983
void node_set_hidden_sockets(bNode *node, int set)
bool node_is_previewable(const SpaceNode &snode, const bNodeTree &ntree, const bNode &node)
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 wmOperatorStatus node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_edit.cc:994
static void compo_canceljob(void *cjv)
Definition node_edit.cc:272
static wmOperatorStatus clear_viewer_border_exec(bContext *C, wmOperator *)
static wmOperatorStatus node_copy_color_exec(bContext *C, wmOperator *)
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)
static wmOperatorStatus node_shader_script_update_exec(bContext *C, wmOperator *op)
static wmOperatorStatus node_options_toggle_exec(bContext *C, wmOperator *)
bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
static void compo_progressjob(void *cjv, float progress)
Definition node_edit.cc:225
VectorSet< bNode * > get_selected_nodes(bNodeTree &node_tree)
static void compo_startjob(void *cjv, wmJobWorkerStatus *worker_status)
Definition node_edit.cc:233
static wmOperatorStatus node_socket_toggle_exec(bContext *C, wmOperator *)
void NODE_OT_preview_toggle(wmOperatorType *ot)
void NODE_OT_clear_viewer_border(wmOperatorType *ot)
static bool compo_breakjob(void *cjv)
Definition node_edit.cc:134
static wmOperatorStatus node_collapse_toggle_exec(bContext *C, wmOperator *)
void snode_set_context(const bContext &C)
Definition node_edit.cc:682
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:199
bool node_has_hidden_sockets(bNode *node)
static wmOperatorStatus test_inline_shader_nodes_exec(bContext *C, wmOperator *)
void NODE_OT_options_toggle(wmOperatorType *ot)
void NODE_OT_toggle_viewer(wmOperatorType *ot)
static wmOperatorStatus viewer_border_exec(bContext *C, wmOperator *op)
static wmOperatorStatus node_duplicate_exec(bContext *C, wmOperator *op)
static wmOperatorStatus node_deactivate_viewer_exec(bContext *C, wmOperator *)
bool composite_node_active(bContext *C)
Definition node_edit.cc:443
static bool socket_is_occluded(const float2 &location, const bNode &node_the_socket_belongs_to, const Span< bNode * > sorted_nodes)
Definition node_edit.cc:873
static void node_resize_init(bContext *C, wmOperator *op, const float2 &cursor, const bNode *node, NodeResizeDirection dir)
Definition node_edit.cc:907
static void compo_initjob(void *cjv)
Definition node_edit.cc:181
static void compo_completejob(void *cjv)
Definition node_edit.cc:283
wmOperatorStatus node_render_changed_exec(bContext *C, wmOperator *)
void NODE_OT_collapse_toggle(wmOperatorType *ot)
static wmOperatorStatus node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void update_multi_input_indices_for_removed_links(bNode &node)
static wmOperatorStatus node_delete_exec(bContext *C, wmOperator *)
void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot)
static wmOperatorStatus node_preview_toggle_exec(bContext *C, wmOperator *)
static wmOperatorStatus node_mute_exec(bContext *C, wmOperator *)
void NODE_OT_mute_toggle(wmOperatorType *ot)
void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node, std::optional< int > item_identifier=std::nullopt)
bNode * find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snode)
T distance(const T &a, const T &b)
bool inline_shader_node_tree(const bNodeTree &src_tree, bNodeTree &dst_tree, InlineShaderNodeTreeParams &params)
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)
void ntreeCompositTagRender(Scene *scene)
blender::bke::bNodeTreeType * ntreeType_Composite
bool ED_node_is_geometry(const SpaceNode *snode)
Definition node_edit.cc:502
void ED_node_texture_default(const bContext *C, Tex *tex)
Definition node_edit.cc:652
void ED_node_set_tree_type(SpaceNode *snode, blender::bke::bNodeTreeType *typeinfo)
Definition node_edit.cc:473
void ED_node_composit_default(const bContext *C, Scene *sce)
Definition node_edit.cc:581
bool ED_node_is_compositor(const SpaceNode *snode)
Definition node_edit.cc:487
void ED_node_composit_default_init(const bContext *C, bNodeTree *ntree)
Definition node_edit.cc:601
void ED_node_set_active(Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
Definition node_edit.cc:728
static bool is_compositing_possible(const bContext *C)
Definition node_edit.cc:303
bool ED_node_is_shader(SpaceNode *snode)
Definition node_edit.cc:492
#define USE_ESC_COMPO
Definition node_edit.cc:87
void ED_node_shader_default(const bContext *C, Main *bmain, ID *id)
Definition node_edit.cc:513
static blender::compositor::OutputTypes get_compositor_needed_outputs(const bContext *C)
Definition node_edit.cc:323
void ED_node_composite_job(const bContext *C, bNodeTree *nodetree, Scene *scene_owner)
Definition node_edit.cc:371
bool ED_node_supports_preview(SpaceNode *snode)
Definition node_edit.cc:507
bool ED_node_is_texture(SpaceNode *snode)
Definition node_edit.cc:497
void ED_node_post_apply_transform(bContext *, bNodeTree *)
Definition node_edit.cc:856
blender::bke::bNodeTreeType * ntreeType_Geometry
#define NODE_MULTI_INPUT_LINK_GAP
#define NODE_SOCKSIZE
#define NODE_DY
return ret
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
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_display_ensure_gpu_context(Render *re)
bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
#define FLT_MAX
Definition stdcycles.h:14
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
char name[258]
Definition DNA_ID.h:432
short source
void * last
void * first
ListBase scenes
Definition BKE_main.hh:278
ListBase materials
Definition BKE_main.hh:284
ListBase worlds
Definition BKE_main.hh:291
struct bNodeTree * nodetree
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
void(* update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node)
Definition RE_engine.h:107
struct ReportList * reports
Definition RE_engine.h:143
struct ToolSettings * toolsettings
SceneRuntimeHandle * runtime
struct bNodeTree * compositing_node_group
struct RenderData r
ListBase view_layers
struct bNodeTree * selected_node_group
char tree_idname[64]
struct ID * from
char node_tree_sub_type
ListBase treepath
struct bNodeTree * edittree
struct ID * id
SpaceNodeOverlay overlay
struct bNodeTree * nodetree
struct bNodeTree * nodetree
char name[64]
ViewerPath viewer_path
struct bNodeTree * nodetree
float horr
bNodeSocketRuntimeHandle * runtime
void * default_value
bNodeTreeRuntimeHandle * runtime
char idname[64]
bNodeTreeTypeHandle * typeinfo
bNodeTreeInterface tree_interface
ListBase nodes
ListBase links
float location[2]
bNodeTypeHandle * typeinfo
int16_t custom1
float width
ListBase inputs
float height
struct ID * id
float color[3]
struct bNode * parent
int16_t type_legacy
void * storage
ListBase outputs
ListBase areabase
bool(* poll)(const bContext *C, bNodeTreeType *ntreetype)
Definition BKE_node.hh:509
void(* get_from_context)(const bContext *C, bNodeTreeType *ntreetype, bNodeTree **r_ntree, ID **r_id, ID **r_from)
Definition BKE_node.hh:511
compositor::OutputTypes needed_outputs
Definition node_edit.cc:111
compositor::Profiler profiler
Definition node_edit.cc:110
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
const void * modal_items
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
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_global_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)
wmOperatorStatus WM_operator_name_call(bContext *C, const char *opstring, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_mousemove(wmWindow *win)
@ RIGHTMOUSE
@ EVT_MODAL_MAP
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(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:376
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:479
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:211
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:397
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:360
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:932
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:959
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)