Blender V4.5
node_add.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 <numeric>
10
12
13#include "MEM_guardedalloc.h"
14
16#include "DNA_node_types.h"
17#include "DNA_texture_types.h"
18
19#include "BLI_easing.h"
20#include "BLI_listbase.h"
21#include "BLI_math_geom.h"
22#include "BLI_string.h"
23
24#include "BLT_translation.hh"
25
26#include "BKE_context.hh"
27#include "BKE_image.hh"
28#include "BKE_lib_id.hh"
29#include "BKE_main.hh"
31#include "BKE_node.hh"
33#include "BKE_node_runtime.hh"
35#include "BKE_report.hh"
36#include "BKE_scene.hh"
37#include "BKE_texture.h"
38
40
42
43#include "ED_asset.hh"
45#include "ED_node.hh" /* own include */
46#include "ED_render.hh"
47#include "ED_screen.hh"
48
49#include "RNA_access.hh"
50#include "RNA_define.hh"
51#include "RNA_enum_types.hh"
52#include "RNA_prototypes.hh"
53
54#include "WM_api.hh"
55#include "WM_types.hh"
56
57#include "UI_view2d.hh"
58
59#include "io_utils.hh"
60#include <fmt/format.h>
61
62#include "node_intern.hh" /* own include */
63
65
66/* -------------------------------------------------------------------- */
69
70static void position_node_based_on_mouse(bNode &node, const float2 &location)
71{
72 node.location[0] = location.x - NODE_DY * 1.5f / UI_SCALE_FAC;
73 node.location[1] = location.y + NODE_DY * 0.5f / UI_SCALE_FAC;
74}
75
76bNode *add_node(const bContext &C, const StringRef idname, const float2 &location)
77{
78 SpaceNode &snode = *CTX_wm_space_node(&C);
79 Main &bmain = *CTX_data_main(&C);
80 bNodeTree &node_tree = *snode.edittree;
81
82 node_deselect_all(node_tree);
83
84 const std::string idname_str = idname;
85
86 bNode *node = bke::node_add_node(&C, node_tree, idname_str.c_str());
87 BLI_assert(node && node->typeinfo);
88
89 position_node_based_on_mouse(*node, location);
90
91 bke::node_set_selected(*node, true);
92 ED_node_set_active(&bmain, &snode, &node_tree, node, nullptr);
93
94 BKE_main_ensure_invariants(bmain, node_tree.id);
95 return node;
96}
97
98bNode *add_static_node(const bContext &C, int type, const float2 &location)
99{
100 SpaceNode &snode = *CTX_wm_space_node(&C);
101 Main &bmain = *CTX_data_main(&C);
102 bNodeTree &node_tree = *snode.edittree;
103
104 node_deselect_all(node_tree);
105
106 bNode *node = bke::node_add_static_node(&C, node_tree, type);
107 BLI_assert(node && node->typeinfo);
108
109 position_node_based_on_mouse(*node, location);
110
111 bke::node_set_selected(*node, true);
112 ED_node_set_active(&bmain, &snode, &node_tree, node, nullptr);
113
114 BKE_main_ensure_invariants(bmain, node_tree.id);
115 return node;
116}
117
119
120/* -------------------------------------------------------------------- */
123
124std::optional<float2> link_path_intersection(const bNodeLink &link, const Span<float2> path)
125{
126 std::array<float2, NODE_LINK_RESOL + 1> coords;
128
129 for (const int i : path.index_range().drop_back(1)) {
130 for (const int j : IndexRange(NODE_LINK_RESOL)) {
132 if (isect_seg_seg_v2_point(path[i], path[i + 1], coords[j], coords[j + 1], result) > 0) {
133 return result;
134 }
135 }
136 }
137
138 return std::nullopt;
139}
140
142 /* The output socket's owner node. */
144 /* Intersected links connected to the socket and their path intersection locations. */
146};
147
149{
150 const ARegion &region = *CTX_wm_region(C);
151 SpaceNode &snode = *CTX_wm_space_node(C);
152 bNodeTree &ntree = *snode.edittree;
153
154 Vector<float2> path;
155 RNA_BEGIN (op->ptr, itemptr, "path") {
156 float2 loc_region;
157 RNA_float_get_array(&itemptr, "loc", loc_region);
158 float2 loc_view;
159 UI_view2d_region_to_view(&region.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y);
160 path.append(loc_view);
161 if (path.size() >= 256) {
162 break;
163 }
164 }
165 RNA_END;
166
167 if (path.is_empty()) {
169 }
170
171 node_deselect_all(ntree);
172
173 ntree.ensure_topology_cache();
174 const Vector<bNode *> frame_nodes = ntree.nodes_by_type("NodeFrame");
175
177
178 /* All link "cuts" that start at a particular output socket. Deduplicating new reroutes per
179 * output socket is useful because it allows reusing reroutes for connected intersections.
180 * Further deduplication using the second map means we only have one cut per link. */
182
183 LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
184 if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
185 continue;
186 }
187 const std::optional<float2> cut = link_path_intersection(*link, path);
188 if (!cut) {
189 continue;
190 }
191 RerouteCutsForSocket &from_cuts = cuts_per_socket.lookup_or_add_default(link->fromsock);
192 from_cuts.from_node = link->fromnode;
193 from_cuts.links.add(link, *cut);
194 }
195
196 for (const auto item : cuts_per_socket.items()) {
197 const Map<bNodeLink *, float2> &cuts = item.value.links;
198
199 bNode *reroute = bke::node_add_static_node(C, ntree, NODE_REROUTE);
200
201 bke::node_add_link(ntree,
202 *item.value.from_node,
203 *item.key,
204 *reroute,
205 *static_cast<bNodeSocket *>(reroute->inputs.first));
206
207 /* Reconnect links from the original output socket to the new reroute. */
208 for (bNodeLink *link : cuts.keys()) {
209 link->fromnode = reroute;
210 link->fromsock = static_cast<bNodeSocket *>(reroute->outputs.first);
212 }
213
214 /* Place the new reroute at the average location of all connected cuts. */
215 const float2 insert_point = std::accumulate(
216 cuts.values().begin(), cuts.values().end(), float2(0)) /
217 cuts.size();
218 reroute->location[0] = insert_point.x / UI_SCALE_FAC;
219 reroute->location[1] = insert_point.y / UI_SCALE_FAC;
220
221 /* Attach the reroute node to frame nodes behind it. */
222 for (const int i : frame_nodes.index_range()) {
223 bNode *frame_node = frame_nodes.last(i);
224 if (BLI_rctf_isect_pt_v(&frame_node->runtime->draw_bounds, insert_point)) {
225 bke::node_attach_node(ntree, *reroute, *frame_node);
226 break;
227 }
228 }
229 }
230
232 return OPERATOR_FINISHED;
233}
234
236{
237 ot->name = "Add Reroute";
238 ot->idname = "NODE_OT_add_reroute";
239 ot->description = "Add a reroute node";
240
241 ot->invoke = WM_gesture_lines_invoke;
242 ot->modal = WM_gesture_lines_modal;
243 ot->exec = add_reroute_exec;
244 ot->cancel = WM_gesture_lines_cancel;
245
247
248 /* flags */
250
251 /* properties */
252 PropertyRNA *prop;
253 prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
255 /* internal */
256 RNA_def_int(ot->srna, "cursor", WM_CURSOR_CROSS, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
257}
258
260
261/* -------------------------------------------------------------------- */
264
265static bool node_group_add_poll(const bNodeTree &node_tree,
266 const bNodeTree &node_group,
268{
269 if (node_group.type != node_tree.type) {
270 return false;
271 }
272
273 const char *disabled_hint = nullptr;
274 if (!bke::node_group_poll(&node_tree, &node_group, &disabled_hint)) {
275 if (disabled_hint) {
277 RPT_ERROR,
278 "Cannot add node group '%s' to '%s':\n %s",
279 node_group.id.name + 2,
280 node_tree.id.name + 2,
281 disabled_hint);
282 }
283 else {
285 RPT_ERROR,
286 "Cannot add node group '%s' to '%s'",
287 node_group.id.name + 2,
288 node_tree.id.name + 2);
289 }
290
291 return false;
292 }
293
294 return true;
295}
296
298{
299 Main *bmain = CTX_data_main(C);
300 SpaceNode *snode = CTX_wm_space_node(C);
301 bNodeTree *ntree = snode->edittree;
302
303 bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
305 if (!node_group) {
306 return OPERATOR_CANCELLED;
307 }
308 if (!node_group_add_poll(*ntree, *node_group, *op->reports)) {
309 return OPERATOR_CANCELLED;
310 }
311
313
314 const StringRef node_idname = node_group_idname(C);
315 if (node_idname[0] == '\0') {
316 BKE_report(op->reports, RPT_WARNING, "Could not determine type of group node");
317 return OPERATOR_CANCELLED;
318 }
319
320 bNode *group_node = add_node(*C, node_idname, snode->runtime->cursor);
321 if (!group_node) {
322 BKE_report(op->reports, RPT_WARNING, "Could not add node group");
323 return OPERATOR_CANCELLED;
324 }
325 if (!RNA_boolean_get(op->ptr, "show_datablock_in_node")) {
326 /* By default, don't show the data-block selector since it's not usually necessary for assets.
327 */
328 group_node->flag &= ~NODE_OPTIONS;
329 }
330 group_node->width = node_group->default_group_node_width;
331
332 group_node->id = &node_group->id;
333 id_us_plus(group_node->id);
335
336 bke::node_set_active(*ntree, *group_node);
340 return OPERATOR_FINISHED;
341}
342
344{
346 return false;
347 }
348 const SpaceNode *snode = CTX_wm_space_node(C);
349 if (snode->edittree->type == NTREE_CUSTOM) {
351 C, "Adding node groups isn't supported for custom (Python defined) node trees");
352 return false;
353 }
354 return true;
355}
356
358{
359 ARegion *region = CTX_wm_region(C);
360 SpaceNode *snode = CTX_wm_space_node(C);
361
362 /* Convert mouse coordinates to v2d space. */
364 event->mval[0],
365 event->mval[1],
366 &snode->runtime->cursor[0],
367 &snode->runtime->cursor[1]);
368
369 snode->runtime->cursor[0] /= UI_SCALE_FAC;
370 snode->runtime->cursor[1] /= UI_SCALE_FAC;
371
372 return node_add_group_exec(C, op);
373}
374
376{
377 /* identifiers */
378 ot->name = "Add Node Group";
379 ot->description = "Add an existing node group to the current node editor";
380 ot->idname = "NODE_OT_add_group";
381
382 /* callbacks */
383 ot->exec = node_add_group_exec;
384 ot->invoke = node_add_group_invoke;
385 ot->poll = node_add_group_poll;
386
387 /* flags */
389
391
393 ot->srna, "show_datablock_in_node", true, "Show the datablock selector in the node", "");
395}
396
398
399/* -------------------------------------------------------------------- */
402
403static bool add_node_group_asset(const bContext &C,
406{
407 Main &bmain = *CTX_data_main(&C);
408 SpaceNode &snode = *CTX_wm_space_node(&C);
409 bNodeTree &edit_tree = *snode.edittree;
410
411 bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
413 if (!node_group) {
414 return false;
415 }
416 if (!node_group_add_poll(edit_tree, *node_group, reports)) {
417 /* Remove the node group if it was newly appended but can't be added to the tree. */
418 id_us_plus(&node_group->id);
419 BKE_id_free_us(&bmain, node_group);
420 return false;
421 }
422
424
425 bNode *group_node = add_node(
426 C, bke::node_tree_type_find(node_group->idname)->group_idname, snode.runtime->cursor);
427 if (!group_node) {
428 BKE_report(&reports, RPT_WARNING, "Could not add node group");
429 return false;
430 }
431 STRNCPY(group_node->name, BKE_id_name(node_group->id));
432 bke::node_unique_name(*snode.edittree, *group_node);
433
434 /* By default, don't show the data-block selector since it's not usually necessary for assets. */
435 group_node->flag &= ~NODE_OPTIONS;
436 group_node->width = node_group->default_group_node_width;
437
438 group_node->id = &node_group->id;
439 id_us_plus(group_node->id);
440 BKE_ntree_update_tag_node_property(&edit_tree, group_node);
441
442 bke::node_set_active(edit_tree, *group_node);
446
447 return true;
448}
449
451 wmOperator *op,
452 const wmEvent *event)
453{
454 ARegion &region = *CTX_wm_region(C);
455 SpaceNode &snode = *CTX_wm_space_node(C);
456
459 if (!asset) {
460 return OPERATOR_CANCELLED;
461 }
462
463 /* Convert mouse coordinates to v2d space. */
465 event->mval[0],
466 event->mval[1],
467 &snode.runtime->cursor[0],
468 &snode.runtime->cursor[1]);
469
470 snode.runtime->cursor /= UI_SCALE_FAC;
471
472 if (!add_node_group_asset(*C, *asset, *op->reports)) {
473 return OPERATOR_CANCELLED;
474 }
475
476 wmOperatorType *ot = WM_operatortype_find("NODE_OT_translate_attach_remove_on_cancel", true);
477 BLI_assert(ot);
482
483 return OPERATOR_FINISHED;
484}
485
487 wmOperatorType * /*ot*/,
489{
492 if (!asset) {
493 return "";
494 }
495 const AssetMetaData &asset_data = asset->get_metadata();
496 if (!asset_data.description) {
497 return "";
498 }
499 return TIP_(asset_data.description);
500}
501
503{
504 ot->name = "Add Node Group Asset";
505 ot->description = "Add a node group asset to the active node tree";
506 ot->idname = "NODE_OT_add_group_asset";
507
509 ot->poll = node_add_group_poll;
510 ot->get_description = node_add_group_asset_get_description;
511
513
515}
516
518
519/* -------------------------------------------------------------------- */
522
524{
525 Main *bmain = CTX_data_main(C);
526 SpaceNode *snode = CTX_wm_space_node(C);
527 bNodeTree *ntree = snode->edittree;
528
529 Object *object = reinterpret_cast<Object *>(
531
532 if (!object) {
533 return OPERATOR_CANCELLED;
534 }
535
537
538 bNode *object_node = add_static_node(*C, GEO_NODE_OBJECT_INFO, snode->runtime->cursor);
539 if (!object_node) {
540 BKE_report(op->reports, RPT_WARNING, "Could not add node object");
541 return OPERATOR_CANCELLED;
542 }
543
544 bNodeSocket *sock = bke::node_find_socket(*object_node, SOCK_IN, "Object");
545 if (!sock) {
547 return OPERATOR_CANCELLED;
548 }
549
551 socket_data->value = object;
552 id_us_plus(&object->id);
554
555 bke::node_set_active(*ntree, *object_node);
556 BKE_main_ensure_invariants(*bmain, ntree->id);
558
559 return OPERATOR_FINISHED;
560}
561
563{
564 ARegion *region = CTX_wm_region(C);
565 SpaceNode *snode = CTX_wm_space_node(C);
566
567 /* Convert mouse coordinates to v2d space. */
569 event->mval[0],
570 event->mval[1],
571 &snode->runtime->cursor[0],
572 &snode->runtime->cursor[1]);
573
574 snode->runtime->cursor[0] /= UI_SCALE_FAC;
575 snode->runtime->cursor[1] /= UI_SCALE_FAC;
576
577 return node_add_object_exec(C, op);
578}
579
581{
582 const SpaceNode *snode = CTX_wm_space_node(C);
584}
585
587{
588 /* identifiers */
589 ot->name = "Add Node Object";
590 ot->description = "Add an object info node to the current node editor";
591 ot->idname = "NODE_OT_add_object";
592
593 /* callbacks */
594 ot->exec = node_add_object_exec;
595 ot->invoke = node_add_object_invoke;
596 ot->poll = node_add_object_poll;
597
598 /* flags */
600
602}
603
605
606/* -------------------------------------------------------------------- */
609
611{
612 Main *bmain = CTX_data_main(C);
613 SpaceNode &snode = *CTX_wm_space_node(C);
614 bNodeTree &ntree = *snode.edittree;
615
616 Collection *collection = reinterpret_cast<Collection *>(
618
619 if (!collection) {
620 return OPERATOR_CANCELLED;
621 }
622
624
625 bNode *collection_node = add_static_node(*C, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor);
626 if (!collection_node) {
627 BKE_report(op->reports, RPT_WARNING, "Could not add node collection");
628 return OPERATOR_CANCELLED;
629 }
630
631 bNodeSocket *sock = bke::node_find_socket(*collection_node, SOCK_IN, "Collection");
632 if (!sock) {
633 BKE_report(op->reports, RPT_WARNING, "Could not find node collection socket");
634 return OPERATOR_CANCELLED;
635 }
636
638 socket_data->value = collection;
639 id_us_plus(&collection->id);
641
642 bke::node_set_active(ntree, *collection_node);
643 BKE_main_ensure_invariants(*bmain, ntree.id);
645
646 return OPERATOR_FINISHED;
647}
648
650 wmOperator *op,
651 const wmEvent *event)
652{
653 ARegion *region = CTX_wm_region(C);
654 SpaceNode *snode = CTX_wm_space_node(C);
655
656 /* Convert mouse coordinates to v2d space. */
658 event->mval[0],
659 event->mval[1],
660 &snode->runtime->cursor[0],
661 &snode->runtime->cursor[1]);
662
663 snode->runtime->cursor[0] /= UI_SCALE_FAC;
664 snode->runtime->cursor[1] /= UI_SCALE_FAC;
665
666 return node_add_collection_exec(C, op);
667}
668
670{
671 const SpaceNode *snode = CTX_wm_space_node(C);
673}
674
676{
677 /* identifiers */
678 ot->name = "Add Node Collection";
679 ot->description = "Add a collection info node to the current node editor";
680 ot->idname = "NODE_OT_add_collection";
681
682 /* callbacks */
686
687 /* flags */
689
691}
692
694
695/* -------------------------------------------------------------------- */
698
700{
701 const SpaceNode *snode = CTX_wm_space_node(C);
702 if (!snode) {
703 return false;
704 }
705
706 /* Note: Validity of snode->nodetree is checked later for better error reporting. */
707 return STR_ELEM(snode->tree_idname,
708 "ShaderNodeTree",
709 "CompositorNodeTree",
710 "TextureNodeTree",
711 "GeometryNodeTree");
712}
713
719
721{
723
724 if (event->type != TIMER || data == nullptr || data->anim_timer != event->customdata) {
726 }
727
728 const float node_stack_anim_duration = 0.25f;
729 const float duration = float(data->anim_timer->time_duration);
730 const float prev_duration = duration - float(data->anim_timer->time_delta);
731 const float clamped_duration = math::min(duration, node_stack_anim_duration);
732 const float delta_factor =
733 BLI_easing_cubic_ease_in_out(clamped_duration, 0.0f, 1.0f, node_stack_anim_duration) -
734 BLI_easing_cubic_ease_in_out(prev_duration, 0.0f, 1.0f, node_stack_anim_duration);
735
736 bool redraw = false;
737 /* Each node is pushed by all previous nodes in the stack. */
738 float stack_offset = 0.0f;
739
740 for (bNode *node : data->nodes) {
741 node->location[1] -= stack_offset;
742 stack_offset += (node->runtime->draw_bounds.ymax - node->runtime->draw_bounds.ymin) *
743 delta_factor;
744 redraw = true;
745 }
746
747 if (redraw) {
749 }
750
751 /* End stack animation. */
752 if (duration > node_stack_anim_duration) {
753 WM_event_timer_remove(CTX_wm_manager(C), nullptr, data->anim_timer);
754 MEM_delete(data);
755 op->customdata = nullptr;
757 }
758
760}
761
763{
764 Main *bmain = CTX_data_main(C);
765 SpaceNode &snode = *CTX_wm_space_node(C);
766 int type = 0;
767 switch (snode.nodetree->type) {
768 case NTREE_SHADER:
769 type = SH_NODE_TEX_IMAGE;
770 break;
771 case NTREE_TEXTURE:
772 type = TEX_NODE_IMAGE;
773 break;
774 case NTREE_COMPOSIT:
775 type = CMP_NODE_IMAGE;
776 break;
777 case NTREE_GEOMETRY:
779 break;
780 default:
781 return OPERATOR_CANCELLED;
782 }
783 Vector<Image *> images;
784 /* Load all paths as ID Images. */
786 for (const std::string &path : paths) {
787 RNA_string_set(op->ptr, "filepath", path.c_str());
788 Image *image = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
789 if (!image) {
790 BKE_report(op->reports, RPT_WARNING, fmt::format("Could not load {}", path).c_str());
791 continue;
792 }
793 images.append(image);
794 /* When adding new image file via drag-drop we need to load #ImBuf in order
795 * to get proper image source. */
796 BKE_image_signal(bmain, image, nullptr, IMA_SIGNAL_RELOAD);
798 }
799
800 /* If not path is provided, try to get a ID Image from operator. */
801 if (paths.is_empty()) {
802 Image *image = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
803 if (image) {
804 images.append(image);
805 }
806 }
807
808 bNodeTree &node_tree = *snode.edittree;
809 float2 position = snode.runtime->cursor;
811 /* Add a node for each image. */
812 for (Image *image : images) {
813 bNode *node = add_static_node(*C, type, position);
814 if (!node) {
815 BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
816 continue;
817 }
818 if (type == GEO_NODE_IMAGE_TEXTURE) {
819 bNodeSocket *image_socket = (bNodeSocket *)node->inputs.first;
820 bNodeSocketValueImage *socket_value = (bNodeSocketValueImage *)image_socket->default_value;
821 socket_value->value = image;
822 BKE_ntree_update_tag_socket_property(&node_tree, image_socket);
823 }
824 else {
825 node->id = (ID *)image;
827 }
828 BKE_ntree_update_tag_node_property(&node_tree, node);
829 nodes.append(node);
830 /* Initial offset between nodes. */
831 position[1] -= 20.0f;
832 }
833
834 if (nodes.is_empty()) {
835 return OPERATOR_CANCELLED;
836 }
837
838 /* Set new nodes as selected. */
839 node_deselect_all(node_tree);
840 for (bNode *node : nodes) {
841 bke::node_set_selected(*node, true);
842 }
843 ED_node_set_active(bmain, &snode, &node_tree, nodes[0], nullptr);
844
846
847 BKE_main_ensure_invariants(*bmain, snode.edittree->id);
849
850 if (nodes.size() == 1) {
851 return OPERATOR_FINISHED;
852 }
853
854 /* Start the stack animation, so each node is placed on top of each other. */
855 NodeStackAnimationData *data = MEM_new<NodeStackAnimationData>(__func__);
856 data->nodes = std::move(nodes);
858 op->customdata = data;
860
862}
863
865{
866 ARegion *region = CTX_wm_region(C);
867 SpaceNode *snode = CTX_wm_space_node(C);
868
871 RPT_ERROR,
872 "Could not add image. A node tree has not been created or assigned");
873 return OPERATOR_CANCELLED;
874 }
875
876 /* Convert mouse coordinates to `v2d` space. */
878 event->mval[0],
879 event->mval[1],
880 &snode->runtime->cursor[0],
881 &snode->runtime->cursor[1]);
882
883 snode->runtime->cursor[0] /= UI_SCALE_FAC;
884 snode->runtime->cursor[1] /= UI_SCALE_FAC;
885
887 RNA_struct_property_is_set(op->ptr, "filepath"))
888 {
889 return node_add_image_exec(C, op);
890 }
891 return WM_operator_filesel(C, op, event);
892}
893
895{
896 /* identifiers */
897 ot->name = "Add Image as Node";
898 ot->description = "Add a image/movie file as node to the current node editor";
899 ot->idname = "NODE_OT_add_image";
900
901 /* callbacks */
902 ot->exec = node_add_image_exec;
903 ot->modal = node_add_nodes_modal;
904 ot->invoke = node_add_image_invoke;
905 ot->poll = node_add_image_poll;
906
907 /* flags */
909
919}
920
922
923/* -------------------------------------------------------------------- */
926
928{
929 SpaceNode *snode = CTX_wm_space_node(C);
930
932}
933
935{
936 Main *bmain = CTX_data_main(C);
937 SpaceNode &snode = *CTX_wm_space_node(C);
938
940 if (!mask) {
941 return OPERATOR_CANCELLED;
942 }
943
945
947
948 if (!node) {
949 BKE_report(op->reports, RPT_WARNING, "Could not add a mask node");
950 return OPERATOR_CANCELLED;
951 }
952
953 node->id = mask;
955
956 BKE_main_ensure_invariants(*bmain, snode.edittree->id);
958
959 return OPERATOR_FINISHED;
960}
961
963{
964 /* identifiers */
965 ot->name = "Add Mask Node";
966 ot->description = "Add a mask node to the current node editor";
967 ot->idname = "NODE_OT_add_mask";
968
969 /* callbacks */
970 ot->exec = node_add_mask_exec;
971 ot->poll = node_add_mask_poll;
972
973 /* flags */
975
977}
978
980
981/* -------------------------------------------------------------------- */
984
986{
987 Main *bmain = CTX_data_main(C);
988 SpaceNode *snode = CTX_wm_space_node(C);
989 bNodeTree *ntree = snode->edittree;
990
991 Material *material = reinterpret_cast<Material *>(
993
994 if (!material) {
995 return OPERATOR_CANCELLED;
996 }
997
999
1000 bNode *material_node = add_static_node(*C, GEO_NODE_INPUT_MATERIAL, snode->runtime->cursor);
1001 if (!material_node) {
1002 BKE_report(op->reports, RPT_WARNING, "Could not add material");
1003 return OPERATOR_CANCELLED;
1004 }
1005
1006 material_node->id = &material->id;
1007 id_us_plus(&material->id);
1008
1009 BKE_main_ensure_invariants(*bmain, ntree->id);
1011
1012 return OPERATOR_FINISHED;
1013}
1014
1016{
1017 ARegion *region = CTX_wm_region(C);
1018 SpaceNode *snode = CTX_wm_space_node(C);
1019
1020 /* Convert mouse coordinates to v2d space. */
1022 event->mval[0],
1023 event->mval[1],
1024 &snode->runtime->cursor[0],
1025 &snode->runtime->cursor[1]);
1026
1027 snode->runtime->cursor[0] /= UI_SCALE_FAC;
1028 snode->runtime->cursor[1] /= UI_SCALE_FAC;
1029
1030 return node_add_material_exec(C, op);
1031}
1032
1034{
1035 const SpaceNode *snode = CTX_wm_space_node(C);
1037}
1038
1040{
1041 /* identifiers */
1042 ot->name = "Add Material";
1043 ot->description = "Add a material node to the current node editor";
1044 ot->idname = "NODE_OT_add_material";
1045
1046 /* callbacks */
1047 ot->exec = node_add_material_exec;
1048 ot->invoke = node_add_material_invoke;
1049 ot->poll = node_add_material_poll;
1050
1051 /* flags */
1053
1055}
1056
1058
1059/* -------------------------------------------------------------------- */
1062
1064{
1065 Main *bmain = CTX_data_main(C);
1066 SpaceNode *snode = CTX_wm_space_node(C);
1067 bNodeTree *ntree = snode->edittree;
1068
1070
1071 Vector<bNode *> new_nodes;
1072 for (const StringRefNull path : paths) {
1073 bNode *node = nullptr;
1074 if (path.endswith(".csv")) {
1075 node = add_node(*C, "GeometryNodeImportCSV", snode->runtime->cursor);
1076 }
1077 else if (path.endswith(".obj")) {
1078 node = add_node(*C, "GeometryNodeImportOBJ", snode->runtime->cursor);
1079 }
1080 else if (path.endswith(".ply")) {
1081 node = add_node(*C, "GeometryNodeImportPLY", snode->runtime->cursor);
1082 }
1083 else if (path.endswith(".stl")) {
1084 node = add_node(*C, "GeometryNodeImportSTL", snode->runtime->cursor);
1085 }
1086 else if (path.endswith(".txt")) {
1087 node = add_node(*C, "GeometryNodeImportText", snode->runtime->cursor);
1088 }
1089 else if (path.endswith(".vdb")) {
1090 node = add_node(*C, "GeometryNodeImportVDB", snode->runtime->cursor);
1091 }
1092
1093 if (node) {
1094 bNodeSocket &path_socket = node->input_by_identifier("Path");
1095 BLI_assert(path_socket.type == SOCK_STRING);
1096 auto *socket_data = static_cast<bNodeSocketValueString *>(path_socket.default_value);
1097 STRNCPY(socket_data->value, path.c_str());
1098 new_nodes.append(node);
1099 }
1100 }
1101
1102 if (new_nodes.is_empty()) {
1103 return OPERATOR_CANCELLED;
1104 }
1105
1106 node_deselect_all(*ntree);
1107
1108 for (const int i : new_nodes.index_range()) {
1109 bNode *node = new_nodes[i];
1110 node->flag |= NODE_SELECT;
1111 }
1112 bke::node_set_active(*ntree, *new_nodes[0]);
1113
1114 NodeStackAnimationData *data = MEM_new<NodeStackAnimationData>(__func__);
1115 data->nodes = std::move(new_nodes);
1116 data->anim_timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.02);
1117 op->customdata = data;
1119
1120 BKE_main_ensure_invariants(*bmain, ntree->id);
1121
1123}
1124
1126 wmOperator *op,
1127 const wmEvent *event)
1128{
1129 ARegion *region = CTX_wm_region(C);
1130 SpaceNode *snode = CTX_wm_space_node(C);
1131
1132 /* Convert mouse coordinates to v2d space. */
1134 event->mval[0],
1135 event->mval[1],
1136 &snode->runtime->cursor[0],
1137 &snode->runtime->cursor[1]);
1138
1139 snode->runtime->cursor[0] /= UI_SCALE_FAC;
1140 snode->runtime->cursor[1] /= UI_SCALE_FAC;
1141
1142 return node_add_import_node_exec(C, op);
1143}
1144
1146{
1147 const SpaceNode *snode = CTX_wm_space_node(C);
1149}
1150
1152{
1153 ot->name = "Add Import Node";
1154 ot->description = "Add an import node to the node tree";
1155 ot->idname = "NODE_OT_add_import_node";
1156
1160 ot->modal = node_add_nodes_modal;
1161
1163
1164 PropertyRNA *prop;
1165
1167 ot->srna, "directory", nullptr, FILE_MAX, "Directory", "Directory of the file");
1169
1170 prop = RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
1172}
1173
1175
1176/* -------------------------------------------------------------------- */
1179
1181{
1182 SpaceNode *snode = CTX_wm_space_node(C);
1183 bNodeTree *ntree = snode->edittree;
1184
1185 bool single_socket = false;
1186 char socket_identifier[int(sizeof(bNodeSocket::idname))];
1187 bool single_panel = false;
1188 int panel_identifier = 0;
1189 if (RNA_struct_property_is_set(op->ptr, "socket_identifier")) {
1190 single_socket = true;
1191 RNA_string_get(op->ptr, "socket_identifier", socket_identifier);
1192 }
1193 if (RNA_struct_property_is_set(op->ptr, "panel_identifier")) {
1194 single_panel = true;
1195 panel_identifier = RNA_int_get(op->ptr, "panel_identifier");
1196 }
1197 if (single_socket && single_panel) {
1198 BKE_report(op->reports, RPT_ERROR, "Cannot set both socket and panel identifier");
1199 return OPERATOR_CANCELLED;
1200 }
1201
1202 bNodeTreeInterfacePanel *interface_panel = nullptr;
1203
1204 if (single_socket) {
1205 /* Ensure the requested socket exists in the node interface. */
1206 bNodeTreeInterfaceSocket *interface_socket = nullptr;
1207 for (bNodeTreeInterfaceSocket *tsocket : ntree->interface_inputs()) {
1208 if (STREQ(socket_identifier, tsocket->identifier)) {
1209 interface_socket = tsocket;
1210 break;
1211 }
1212 }
1213 if (!interface_socket) {
1214 BKE_report(
1215 op->reports,
1216 RPT_ERROR,
1217 fmt::format("Invalid socket_identifier: Socket \"%s\" not found", socket_identifier)
1218 .c_str());
1219 return OPERATOR_CANCELLED;
1220 }
1221 }
1222 if (single_panel) {
1223 /* Ensure the requested panel exists in the node interface. */
1224 for (bNodeTreeInterfaceItem *item : ntree->interface_items()) {
1226 item);
1227 if (tpanel && tpanel->identifier == panel_identifier) {
1228 interface_panel = tpanel;
1229 break;
1230 }
1231 }
1232
1233 if (!interface_panel) {
1234 BKE_report(op->reports, RPT_ERROR, "Invalid panel identifier");
1235 return OPERATOR_CANCELLED;
1236 }
1237 }
1238
1240
1241 bNode *group_input_node = add_node(*C, "NodeGroupInput", snode->runtime->cursor);
1242
1243 if (single_socket) {
1244 /* Hide all other sockets in the new node, to only display the selected one. */
1245 LISTBASE_FOREACH (bNodeSocket *, socket, &group_input_node->outputs) {
1246 if (!STREQ(socket->identifier, socket_identifier)) {
1247 socket->flag |= SOCK_HIDDEN;
1248 }
1249 }
1250 }
1251 if (single_panel) {
1252 /* Initially hide all sockets. */
1253 LISTBASE_FOREACH (bNodeSocket *, socket, &group_input_node->outputs) {
1254 socket->flag |= SOCK_HIDDEN;
1255 }
1256 /* Show only sockets contained in the dragged panel. */
1257 for (bNodeTreeInterfaceSocket *iface_socket : ntree->interface_inputs()) {
1258 if (interface_panel->contains_recursive(iface_socket->item)) {
1260 *group_input_node, SOCK_OUT, iface_socket->identifier);
1261 BLI_assert(socket);
1262 socket->flag &= ~SOCK_HIDDEN;
1263 }
1264 }
1265 }
1266
1267 return OPERATOR_FINISHED;
1268}
1269
1271 wmOperator *op,
1272 const wmEvent *event)
1273{
1274 ARegion *region = CTX_wm_region(C);
1275 SpaceNode *snode = CTX_wm_space_node(C);
1276
1277 /* Convert mouse coordinates to v2d space. */
1279 event->mval[0],
1280 event->mval[1],
1281 &snode->runtime->cursor[0],
1282 &snode->runtime->cursor[1]);
1283
1284 snode->runtime->cursor[0] /= UI_SCALE_FAC;
1285 snode->runtime->cursor[1] /= UI_SCALE_FAC;
1286
1288}
1289
1291{
1293 return false;
1294 }
1295
1296 const SpaceNode *snode = CTX_wm_space_node(C);
1297 bNodeTree *ntree = snode->edittree;
1298
1299 bNodeTreeInterface interface = ntree->tree_interface;
1300 bNodeTreeInterfaceItem *active_item = interface.active_item();
1301
1302 if (auto *socket = bke::node_interface::get_item_as<bNodeTreeInterfaceSocket>(active_item)) {
1303 if (socket->flag & NODE_INTERFACE_SOCKET_OUTPUT) {
1304 CTX_wm_operator_poll_msg_set(C, "Cannot drag an output socket");
1305 return false;
1306 }
1307 return true;
1308 }
1309
1310 if (auto *panel = bke::node_interface::get_item_as<bNodeTreeInterfacePanel>(active_item)) {
1311 bool has_inputs = false;
1312 for (bNodeTreeInterfaceSocket *socket : ntree->interface_inputs()) {
1313 if (panel->contains_recursive(socket->item)) {
1314 has_inputs = true;
1315 break;
1316 }
1317 }
1318
1319 if (!has_inputs) {
1320 CTX_wm_operator_poll_msg_set(C, "Cannot drag panel with no inputs");
1321 return false;
1322 }
1323 return true;
1324 }
1325 return false;
1326}
1327
1329{
1330 ot->name = "Add Group Input Node";
1331 ot->description = "Add a Group Input node with selected sockets to the current node editor";
1332 ot->idname = "NODE_OT_add_group_input_node";
1333
1337
1339
1340 PropertyRNA *prop = RNA_def_string(ot->srna,
1341 "socket_identifier",
1342 nullptr,
1343 int(sizeof(bNodeSocket::idname)),
1344 "Socket Identifier",
1345 "Socket to include in the added group input/output node");
1347 prop = RNA_def_int(ot->srna,
1348 "panel_identifier",
1349 0,
1350 INT_MIN,
1351 INT_MAX,
1352 "Panel Identifier",
1353 "Panel from which to add sockets to the added group input/output node",
1354 INT_MIN,
1355 INT_MAX);
1357}
1358
1360
1361/* -------------------------------------------------------------------- */
1364
1366{
1367 Main *bmain = CTX_data_main(C);
1368 SpaceNode *snode = CTX_wm_space_node(C);
1369 bNodeTree *ntree = snode->edittree;
1370
1371 float color[4];
1372 RNA_float_get_array(op->ptr, "color", color);
1373 const bool gamma = RNA_boolean_get(op->ptr, "gamma");
1374 const bool has_alpha = RNA_boolean_get(op->ptr, "has_alpha");
1375
1376 if (!has_alpha) {
1377 color[3] = 1.0f;
1378 }
1379
1380 if (gamma) {
1382 }
1383
1384 bNode *color_node;
1385
1386 switch (snode->nodetree->type) {
1387 case NTREE_SHADER:
1388 color_node = add_node(*C, "ShaderNodeRGB", snode->runtime->cursor);
1389 break;
1390 case NTREE_COMPOSIT:
1391 color_node = add_node(*C, "CompositorNodeRGB", snode->runtime->cursor);
1392 break;
1393 case NTREE_GEOMETRY:
1394 color_node = add_node(*C, "FunctionNodeInputColor", snode->runtime->cursor);
1395 break;
1396 default:
1397 return OPERATOR_CANCELLED;
1398 }
1399
1400 if (!color_node) {
1401 BKE_report(op->reports, RPT_WARNING, "Could not add a color node");
1402 return OPERATOR_CANCELLED;
1403 }
1404
1405 /* The Geometry Node color node stores the color value inside the node storage, while
1406 * the Compositing and Shading color nodes store it in the output socket. */
1407 if (snode->nodetree->type == NTREE_GEOMETRY) {
1408 NodeInputColor *input_color_storage = static_cast<NodeInputColor *>(color_node->storage);
1409 copy_v4_v4(input_color_storage->color, color);
1410 }
1411 else {
1412 bNodeSocket *sock = static_cast<bNodeSocket *>(color_node->outputs.first);
1413 if (!sock) {
1414 BKE_report(op->reports, RPT_WARNING, "Could not find node color socket");
1415 return OPERATOR_CANCELLED;
1416 }
1417
1418 bNodeSocketValueRGBA *socket_data = static_cast<bNodeSocketValueRGBA *>(sock->default_value);
1419 copy_v4_v4(socket_data->value, color);
1420 }
1421
1422 bke::node_set_active(*ntree, *color_node);
1423 BKE_main_ensure_invariants(*bmain, ntree->id);
1424
1425 return OPERATOR_FINISHED;
1426}
1427
1429{
1430 ARegion *region = CTX_wm_region(C);
1431 SpaceNode *snode = CTX_wm_space_node(C);
1432
1433 /* Convert mouse coordinates to v2d space. */
1435 event->mval[0],
1436 event->mval[1],
1437 &snode->runtime->cursor[0],
1438 &snode->runtime->cursor[1]);
1439
1440 snode->runtime->cursor[0] /= UI_SCALE_FAC;
1441 snode->runtime->cursor[1] /= UI_SCALE_FAC;
1442
1443 return node_add_color_exec(C, op);
1444}
1445
1447{
1448 const SpaceNode *snode = CTX_wm_space_node(C);
1449 return ED_operator_node_editable(C) &&
1451}
1452
1454{
1455 /* identifiers */
1456 ot->name = "Add Color";
1457 ot->description = "Add a color node to the current node editor";
1458 ot->idname = "NODE_OT_add_color";
1459
1460 /* callbacks */
1461 ot->exec = node_add_color_exec;
1462 ot->invoke = node_add_color_invoke;
1463 ot->poll = node_add_color_poll;
1464
1465 /* flags */
1467
1469 ot->srna, "color", 4, nullptr, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
1471 ot->srna, "gamma", false, "Gamma Corrected", "The source color is gamma corrected");
1473 ot->srna, "has_alpha", false, "Has Alpha", "The source color contains an Alpha component");
1474}
1475
1476/* -------------------------------------------------------------------- */
1479
1481{
1482 SpaceNode *snode = CTX_wm_space_node(C);
1483 Main *bmain = CTX_data_main(C);
1484 bNodeTree *ntree;
1486 PropertyRNA *prop;
1487 const char *idname;
1488 char treename_buf[MAX_ID_NAME - 2];
1489 const char *treename;
1490
1491 if (RNA_struct_property_is_set(op->ptr, "type")) {
1492 prop = RNA_struct_find_property(op->ptr, "type");
1493 RNA_property_enum_identifier(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &idname);
1494 }
1495 else if (snode) {
1496 idname = snode->tree_idname;
1497 }
1498 else {
1499 return OPERATOR_CANCELLED;
1500 }
1501
1502 if (!bke::node_tree_type_find(idname)) {
1503 BKE_reportf(op->reports, RPT_ERROR, "Node tree type %s undefined", idname);
1504 return OPERATOR_CANCELLED;
1505 }
1506
1507 if (RNA_struct_property_is_set(op->ptr, "name")) {
1508 RNA_string_get(op->ptr, "name", treename_buf);
1509 treename = treename_buf;
1510 }
1511 else {
1512 const bke::bNodeTreeType *type = bke::node_tree_type_find(idname);
1513 treename = type->ui_name.c_str();
1514 }
1515
1516 ntree = bke::node_tree_add_tree(bmain, treename, idname);
1517
1518 /* Hook into UI. */
1520
1521 if (prop) {
1522 /* #RNA_property_pointer_set increases the user count, fixed here as the editor is the initial
1523 * user. */
1524 id_us_min(&ntree->id);
1525
1526 if (ptr.owner_id) {
1527 BKE_id_move_to_same_lib(*bmain, ntree->id, *ptr.owner_id);
1528 }
1529
1530 PointerRNA idptr = RNA_id_pointer_create(&ntree->id);
1531 RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
1532 RNA_property_update(C, &ptr, prop);
1533 }
1534 else if (snode) {
1535 snode->nodetree = ntree;
1536
1537 tree_update(C);
1538 }
1539
1541
1542 return OPERATOR_FINISHED;
1543}
1544
1546 PointerRNA * /*ptr*/,
1547 PropertyRNA * /*prop*/,
1548 bool *r_free)
1549{
1550 return rna_node_tree_type_itemf(nullptr, nullptr, r_free);
1551}
1552
1554{
1555 PropertyRNA *prop;
1556
1557 /* identifiers */
1558 ot->name = "New Node Tree";
1559 ot->idname = "NODE_OT_new_node_tree";
1560 ot->description = "Create a new node tree";
1561
1562 /* API callbacks. */
1563 ot->exec = new_node_tree_exec;
1564
1565 /* flags */
1566 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1567
1568 prop = RNA_def_enum(ot->srna, "type", rna_enum_dummy_NULL_items, 0, "Tree Type", "");
1570 RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME - 2, "Name", "");
1571}
1572
1574
1575} // namespace blender::ed::space_node
Main runtime representation of an asset.
SpaceNode * CTX_wm_space_node(const bContext *C)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
wmWindow * CTX_wm_window(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define IMA_SIGNAL_RELOAD
Definition BKE_image.hh:161
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
void BKE_id_free_us(Main *bmain, void *idv) ATTR_NONNULL()
void id_us_plus(ID *id)
Definition lib_id.cc:353
void BKE_id_move_to_same_lib(Main &bmain, ID &id, const ID &owner_id)
Definition lib_id.cc:869
const char * BKE_id_name(const ID &id)
void id_us_min(ID *id)
Definition lib_id.cc:361
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
#define NODE_REROUTE
Definition BKE_node.hh:798
#define CMP_NODE_MASK
#define GEO_NODE_OBJECT_INFO
#define SH_NODE_TEX_IMAGE
#define GEO_NODE_IMAGE_TEXTURE
#define TEX_NODE_IMAGE
#define GEO_NODE_INPUT_MATERIAL
#define CMP_NODE_IMAGE
#define GEO_NODE_COLLECTION_INFO
void BKE_ntree_update_tag_link_changed(bNodeTree *ntree)
void BKE_ntree_update_tag_socket_property(bNodeTree *ntree, bNodeSocket *socket)
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:108
#define LISTBASE_FOREACH(type, var, list)
int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
MINLINE void copy_v4_v4(float r[4], const float a[4])
#define FILE_MAX
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
#define STR_ELEM(...)
Definition BLI_string.h:656
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define ELEM(...)
#define STREQ(a, b)
#define TIP_(msgid)
void DEG_relations_tag_update(Main *bmain)
@ ID_IM
@ ID_NT
@ ID_MSK
@ ID_MA
@ ID_GR
@ ID_OB
Object groups, one object can be in many groups at once.
@ NTREE_TEXTURE
@ NTREE_CUSTOM
@ NTREE_SHADER
@ NTREE_GEOMETRY
@ NTREE_COMPOSIT
@ SOCK_OUT
@ SOCK_IN
@ NODE_OPTIONS
@ NODE_SELECT
@ SOCK_HIDDEN
@ SOCK_STRING
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_MOVIE
@ FILE_TYPE_FOLDER
@ FILE_TYPE_IMAGE
@ FILE_DEFAULTDISPLAY
#define UI_SCALE_FAC
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_node_set_active(Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
Definition node_edit.cc:772
void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
bool ED_operator_node_editable(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
Read Guarded memory(de)allocation.
#define RNA_BEGIN(sptr, itemptr, propname)
#define RNA_END
const EnumPropertyItem * rna_node_tree_type_itemf(void *data, bool(*poll)(void *data, blender::bke::bNodeTreeType *), bool *r_free)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
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:1667
@ WM_FILESEL_FILES
Definition WM_api.hh:1076
@ WM_FILESEL_DIRECTORY
Definition WM_api.hh:1073
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1072
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1075
@ FILE_OPENFILE
Definition WM_api.hh:1084
#define NC_NODE
Definition WM_types.hh:391
#define NA_ADDED
Definition WM_types.hh:583
#define NA_EDITED
Definition WM_types.hh:581
ReportList * reports
Definition WM_types.hh:1025
#define NC_IMAGE
Definition WM_types.hh:381
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:218
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
BMesh const char void * data
SubIterator begin() const
Definition BLI_map.hh:768
SubIterator end() const
Definition BLI_map.hh:778
constexpr IndexRange drop_back(int64_t n) const
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:639
ValueIterator values() const &
Definition BLI_map.hh:884
int64_t size() const
Definition BLI_map.hh:976
KeyIterator keys() const &
Definition BLI_map.hh:875
ItemIterator items() const &
Definition BLI_map.hh:902
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
int64_t size() const
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
IndexRange index_range() const
#define MAX_ID_NAME
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
T & get_item_as(bNodeTreeInterfaceItem &item)
void node_attach_node(bNodeTree &ntree, bNode &node, bNode &parent)
Definition node.cc:4255
bNodeTreeType * node_tree_type_find(StringRef idname)
Definition node.cc:2635
void node_tag_update_id(bNode &node)
Definition node.cc:5105
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2864
bNode * node_add_node(const bContext *C, bNodeTree &ntree, StringRef idname)
Definition node.cc:3788
bool node_group_poll(const bNodeTree *nodetree, const bNodeTree *grouptree, const char **r_disabled_hint)
bool node_set_selected(bNode &node, bool select)
Definition node.cc:4967
bNode * node_add_static_node(const bContext *C, bNodeTree &ntree, int type)
Definition node.cc:3804
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:4087
bNodeTree * node_tree_add_tree(Main *bmain, StringRef name, StringRef idname)
Definition node.cc:4362
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4996
void node_unique_name(bNodeTree &ntree, bNode &node)
Definition node.cc:3764
ID * asset_local_id_ensure_imported(Main &bmain, const asset_system::AssetRepresentation &asset)
void operator_asset_reference_props_register(StructRNA &srna)
const asset_system::AssetRepresentation * operator_asset_reference_props_get_asset_from_all_library(const bContext &C, PointerRNA &ptr, ReportList *reports)
Vector< std::string > paths_from_operator_properties(PointerRNA *ptr)
Definition io_utils.cc:75
void NODE_OT_add_group_input_node(wmOperatorType *ot)
Definition node_add.cc:1328
void NODE_OT_add_object(wmOperatorType *ot)
Definition node_add.cc:586
static bool node_add_material_poll(bContext *C)
Definition node_add.cc:1033
static wmOperatorStatus node_add_group_exec(bContext *C, wmOperator *op)
Definition node_add.cc:297
void NODE_OT_add_mask(wmOperatorType *ot)
Definition node_add.cc:962
static bool node_add_object_poll(bContext *C)
Definition node_add.cc:580
static wmOperatorStatus add_reroute_exec(bContext *C, wmOperator *op)
Definition node_add.cc:148
bNode * add_static_node(const bContext &C, int type, const float2 &location)
Definition node_add.cc:98
static wmOperatorStatus node_add_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:1428
static wmOperatorStatus node_add_mask_exec(bContext *C, wmOperator *op)
Definition node_add.cc:934
static bool node_add_image_poll(bContext *C)
Definition node_add.cc:699
static bool node_add_group_poll(bContext *C)
Definition node_add.cc:343
void NODE_OT_add_reroute(wmOperatorType *ot)
Definition node_add.cc:235
static wmOperatorStatus node_add_collection_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:649
bool node_deselect_all(bNodeTree &node_tree)
static wmOperatorStatus node_add_import_node_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:1125
void NODE_OT_add_collection(wmOperatorType *ot)
Definition node_add.cc:675
bNode * add_node(const bContext &C, const StringRef idname, const float2 &location)
Definition node_add.cc:76
static wmOperatorStatus node_add_group_input_node_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1180
void NODE_OT_add_group_asset(wmOperatorType *ot)
Definition node_add.cc:502
static wmOperatorStatus node_add_material_exec(bContext *C, wmOperator *op)
Definition node_add.cc:985
static void position_node_based_on_mouse(bNode &node, const float2 &location)
Definition node_add.cc:70
static bool node_add_color_poll(bContext *C)
Definition node_add.cc:1446
static wmOperatorStatus node_add_collection_exec(bContext *C, wmOperator *op)
Definition node_add.cc:610
static const EnumPropertyItem * new_node_tree_type_itemf(bContext *, PointerRNA *, PropertyRNA *, bool *r_free)
Definition node_add.cc:1545
static bool node_add_import_node_poll(bContext *C)
Definition node_add.cc:1145
void NODE_OT_add_color(wmOperatorType *ot)
Definition node_add.cc:1453
static wmOperatorStatus node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:450
static wmOperatorStatus node_add_material_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:1015
bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
void tree_update(const bContext *C)
Definition node_draw.cc:169
std::optional< float2 > link_path_intersection(const bNodeLink &link, const Span< float2 > path)
Definition node_add.cc:124
static bool node_group_add_poll(const bNodeTree &node_tree, const bNodeTree &node_group, ReportList &reports)
Definition node_add.cc:265
static wmOperatorStatus node_add_object_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:562
void node_link_bezier_points_evaluated(const bNodeLink &link, std::array< float2, NODE_LINK_RESOL+1 > &coords)
Definition drawnode.cc:1704
static bool node_add_mask_poll(bContext *C)
Definition node_add.cc:927
static wmOperatorStatus node_add_object_exec(bContext *C, wmOperator *op)
Definition node_add.cc:523
static bool node_add_group_input_node_poll(bContext *C)
Definition node_add.cc:1290
void NODE_OT_add_import_node(wmOperatorType *ot)
Definition node_add.cc:1151
static std::string node_add_group_asset_get_description(bContext *C, wmOperatorType *, PointerRNA *ptr)
Definition node_add.cc:486
void NODE_OT_add_image(wmOperatorType *ot)
Definition node_add.cc:894
static wmOperatorStatus new_node_tree_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1480
void NODE_OT_add_group(wmOperatorType *ot)
Definition node_add.cc:375
static wmOperatorStatus node_add_nodes_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:720
static wmOperatorStatus node_add_color_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1365
static bool node_add_collection_poll(bContext *C)
Definition node_add.cc:669
static wmOperatorStatus node_add_import_node_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1063
static wmOperatorStatus node_add_group_input_node_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:1270
static wmOperatorStatus node_add_group_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:357
void NODE_OT_add_material(wmOperatorType *ot)
Definition node_add.cc:1039
static wmOperatorStatus node_add_image_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:864
static wmOperatorStatus node_add_image_exec(bContext *C, wmOperator *op)
Definition node_add.cc:762
void NODE_OT_new_node_tree(wmOperatorType *ot)
Definition node_add.cc:1553
StringRef node_group_idname(const bContext *C)
static bool add_node_group_asset(const bContext &C, const asset_system::AssetRepresentation &asset, ReportList &reports)
Definition node_add.cc:403
T min(const T &a, const T &b)
VecBase< float, 2 > float2
#define NODE_LINK_RESOL
#define NODE_DY
bool RNA_property_enum_identifier(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_identifier)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
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_float_color(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
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_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, 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)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
PropertyRNA * RNA_def_string_dir_path(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_dummy_NULL_items[]
Definition rna_rna.cc:26
#define FLT_MAX
Definition stdcycles.h:14
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
void * first
char tree_idname[64]
SpaceNode_Runtime * runtime
struct bNodeTree * edittree
struct bNodeTree * nodetree
struct Collection * value
void * default_value
char idname[64]
char idname[64]
int default_group_node_width
ListBase links
float location[2]
bNodeTypeHandle * typeinfo
float width
ListBase inputs
struct ID * id
char name[64]
bNodeRuntimeHandle * runtime
void * storage
ListBase outputs
wmEventType type
Definition WM_types.hh:754
int mval[2]
Definition WM_types.hh:760
void * customdata
Definition WM_types.hh:804
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
@ WM_CURSOR_CROSS
Definition wm_cursors.hh:26
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ TIMER
PointerRNA * ptr
Definition wm_files.cc:4227
wmOperatorType * ot
Definition wm_files.cc:4226
void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_lines_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_lines_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool WM_operator_properties_id_lookup_is_set(PointerRNA *ptr)
ID * WM_operator_properties_id_lookup_from_name_or_session_uid(Main *bmain, PointerRNA *ptr, const ID_Type type)
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
ID * WM_operator_drop_load_path(bContext *C, wmOperator *op, const short idcode)
wmOperatorStatus WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)