Blender V4.3
node_tree_interface.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_idprop.hh"
6#include "BKE_lib_id.hh"
7#include "BKE_lib_query.hh"
8#include "BKE_node.hh"
9#include "BKE_node_enum.hh"
11
12#include "BLI_math_vector.h"
13#include "BLI_stack.hh"
14#include "BLI_string.h"
15#include "BLI_vector.hh"
16
17#include "BLO_read_write.hh"
18
20#include "DNA_material_types.h"
22#include "DNA_node_types.h"
23
32
34
35namespace socket_types {
36
37/* Try to get a supported socket type from some final type.
38 * Built-in socket can have multiple registered RNA types for the base type, e.g.
39 * `NodeSocketFloatUnsigned`, `NodeSocketFloatFactor`. Only the "base type" (`NodeSocketFloat`)
40 * is considered valid for interface sockets.
41 */
42static const char *try_get_supported_socket_type(const StringRef socket_type)
43{
44 /* Make a copy of the string for `.c_str()` until the socket type map uses C++ types. */
45 const std::string idname(socket_type);
46 const blender::bke::bNodeSocketType *typeinfo = bke::node_socket_type_find(idname.c_str());
47 if (typeinfo == nullptr) {
48 return nullptr;
49 }
50 /* For builtin socket types only the base type is supported. */
51 if (node_is_static_socket_type(typeinfo)) {
53 }
54 return typeinfo->idname;
55}
56
57/* -------------------------------------------------------------------- */
60
61template<typename T> void socket_data_id_user_increment(T & /*data*/) {}
63{
64 id_us_plus(reinterpret_cast<ID *>(data.value));
65}
67{
68 id_us_plus(reinterpret_cast<ID *>(data.value));
69}
71{
72 id_us_plus(reinterpret_cast<ID *>(data.value));
73}
75{
76 id_us_plus(reinterpret_cast<ID *>(data.value));
77}
79{
80 id_us_plus(reinterpret_cast<ID *>(data.value));
81}
82
84
85/* -------------------------------------------------------------------- */
88
89template<typename T> void socket_data_id_user_decrement(T & /*data*/) {}
91{
92 id_us_min(reinterpret_cast<ID *>(data.value));
93}
95{
96 id_us_min(reinterpret_cast<ID *>(data.value));
97}
99{
100 id_us_min(reinterpret_cast<ID *>(data.value));
101}
103{
104 id_us_min(reinterpret_cast<ID *>(data.value));
105}
107{
108 id_us_min(reinterpret_cast<ID *>(data.value));
109}
110
112
113/* -------------------------------------------------------------------- */
116
117template<typename T> void socket_data_init_impl(T & /*data*/) {}
119{
120 data.subtype = PROP_NONE;
121 data.value = 0.0f;
122 data.min = -FLT_MAX;
123 data.max = FLT_MAX;
124}
126{
127 data.subtype = PROP_NONE;
128 data.value = 0;
129 data.min = INT_MIN;
130 data.max = INT_MAX;
131}
133{
134 data.value = false;
135}
138{
139 static float default_value[] = {0.0f, 0.0f, 0.0f};
140 data.subtype = PROP_NONE;
141 copy_v3_v3(data.value, default_value);
142 data.min = -FLT_MAX;
143 data.max = FLT_MAX;
144}
146{
147 static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f};
148 copy_v4_v4(data.value, default_value);
149}
151{
152 data.subtype = PROP_NONE;
153 data.value[0] = '\0';
154}
156{
157 data.value = nullptr;
158}
160{
161 data.value = nullptr;
162}
164{
165 data.value = nullptr;
166}
168{
169 data.value = nullptr;
170}
172{
173 data.value = nullptr;
174}
176{
177 data.value = -1;
178 data.enum_items = nullptr;
179 data.runtime_flag = 0;
180}
181
182static void *make_socket_data(const StringRef socket_type)
183{
184 void *socket_data = nullptr;
185 socket_data_to_static_type_tag(socket_type, [&socket_data](auto type_tag) {
186 using SocketDataType = typename decltype(type_tag)::type;
187 SocketDataType *new_socket_data = MEM_cnew<SocketDataType>(__func__);
188 socket_data_init_impl(*new_socket_data);
189 socket_data = new_socket_data;
190 });
191 return socket_data;
192}
193
195
196/* -------------------------------------------------------------------- */
199
200template<typename T> void socket_data_free_impl(T & /*data*/, const bool /*do_id_user*/) {}
201template<> void socket_data_free_impl(bNodeSocketValueMenu &dst, const bool /*do_id_user*/)
202{
203 if (dst.enum_items) {
204 /* Release shared data pointer. */
205 dst.enum_items->remove_user_and_delete_if_last();
206 }
207}
208
209static void socket_data_free(bNodeTreeInterfaceSocket &socket, const bool do_id_user)
210{
211 socket_data_to_static_type_tag(socket.socket_type, [&](auto type_tag) {
212 using SocketDataType = typename decltype(type_tag)::type;
213 if (do_id_user) {
214 socket_data_id_user_decrement(get_socket_data_as<SocketDataType>(socket));
215 }
217 });
218}
219
221
222/* -------------------------------------------------------------------- */
225
226template<typename T> void socket_data_copy_impl(T & /*dst*/, const T & /*src*/) {}
227template<>
229{
230 /* Copy of shared data pointer. */
231 if (dst.enum_items) {
232 dst.enum_items->add_user();
233 }
234}
235
237 const bNodeTreeInterfaceSocket &src,
238 int flag)
239{
240 socket_data_to_static_type_tag(dst.socket_type, [&](auto type_tag) {
241 using SocketDataType = typename decltype(type_tag)::type;
242 dst.socket_data = MEM_dupallocN(src.socket_data);
243 socket_data_copy_impl(get_socket_data_as<SocketDataType>(dst),
244 get_socket_data_as<SocketDataType>(src));
245 if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
246 socket_data_id_user_increment(get_socket_data_as<SocketDataType>(dst));
247 }
248 });
249}
250
251/* Copy socket data from a raw pointer, e.g. from a #bNodeSocket. */
253 const void *src_socket_data,
254 int flag)
255{
256 socket_data_to_static_type_tag(dst.socket_type, [&](auto type_tag) {
257 using SocketDataType = typename decltype(type_tag)::type;
258
259 if (dst.socket_data != nullptr) {
260 socket_data_free(dst, true);
261 MEM_SAFE_FREE(dst.socket_data);
262 }
263
264 dst.socket_data = MEM_dupallocN(src_socket_data);
266 *static_cast<const SocketDataType *>(src_socket_data));
269 }
270 });
271}
272
274
275/* -------------------------------------------------------------------- */
278
279/* NOTE: no default implementation, every used type must write at least the base struct. */
280
333
335{
336 socket_data_to_static_type_tag(socket.socket_type, [&](auto type_tag) {
337 using SocketDataType = typename decltype(type_tag)::type;
338 socket_data_write_impl(writer, get_socket_data_as<SocketDataType>(socket));
339 });
340}
341
343
344/* -------------------------------------------------------------------- */
347
348template<typename T> void socket_data_read_data_impl(BlendDataReader *reader, T **data)
349{
350 /* FIXME Avoid using low-level untyped read function here. Cannot use the BLO_read_struct
351 * currently (macro expansion would process `T` instead of the actual type). */
353}
355{
356 /* FIXME Avoid using low-level untyped read function here. No type info available here currently.
357 */
359 /* Clear runtime data. */
360 (*data)->enum_items = nullptr;
361 (*data)->runtime_flag = 0;
362}
363
365{
366 bool data_read = false;
367 socket_data_to_static_type_tag(socket.socket_type, [&](auto type_tag) {
368 using SocketDataType = typename decltype(type_tag)::type;
369 socket_data_read_data_impl(reader, reinterpret_cast<SocketDataType **>(&socket.socket_data));
370 data_read = true;
371 });
372 if (!data_read && socket.socket_data) {
373 /* Not sure how this can happen exactly, but it did happen in #127855. */
374 socket.socket_data = nullptr;
375 }
376}
377
379
380/* -------------------------------------------------------------------- */
383
384template<typename T>
386{
387}
396template<>
401template<>
406template<>
411
413{
414 socket_data_to_static_type_tag(socket.socket_type, [&](auto type_tag) {
415 using SocketDataType = typename decltype(type_tag)::type;
416 socket_data_foreach_id_impl(data, get_socket_data_as<SocketDataType>(socket));
417 });
418}
419
421
422} // namespace socket_types
423
424namespace item_types {
425
427
428static void item_copy(bNodeTreeInterfaceItem &dst,
429 const bNodeTreeInterfaceItem &src,
430 int flag,
431 UidGeneratorFn generate_uid);
432
440 const int flag,
441 UidGeneratorFn generate_uid)
442{
443 panel.items_num = items_src.size();
444 panel.items_array = MEM_cnew_array<bNodeTreeInterfaceItem *>(panel.items_num, __func__);
445
446 /* Copy buffers. */
447 for (const int i : items_src.index_range()) {
448 const bNodeTreeInterfaceItem *item_src = items_src[i];
449 panel.items_array[i] = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(item_src));
450 item_types::item_copy(*panel.items_array[i], *item_src, flag, generate_uid);
451 }
452}
453
460 const bNodeTreeInterfaceItem &src,
461 const int flag,
462 UidGeneratorFn generate_uid)
463{
464 switch (dst.item_type) {
466 bNodeTreeInterfaceSocket &dst_socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(dst);
467 const bNodeTreeInterfaceSocket &src_socket =
468 reinterpret_cast<const bNodeTreeInterfaceSocket &>(src);
469 BLI_assert(src_socket.socket_type != nullptr);
470
471 dst_socket.name = BLI_strdup_null(src_socket.name);
472 dst_socket.description = BLI_strdup_null(src_socket.description);
473 dst_socket.socket_type = BLI_strdup(src_socket.socket_type);
475 dst_socket.identifier = generate_uid ? BLI_sprintfN("Socket_%d", generate_uid()) :
476 BLI_strdup(src_socket.identifier);
477 if (src_socket.properties) {
478 dst_socket.properties = IDP_CopyProperty_ex(src_socket.properties, flag);
479 }
480 if (src_socket.socket_data != nullptr) {
481 socket_types::socket_data_copy(dst_socket, src_socket, flag);
482 }
483 break;
484 }
486 bNodeTreeInterfacePanel &dst_panel = reinterpret_cast<bNodeTreeInterfacePanel &>(dst);
487 const bNodeTreeInterfacePanel &src_panel = reinterpret_cast<const bNodeTreeInterfacePanel &>(
488 src);
489
490 dst_panel.name = BLI_strdup_null(src_panel.name);
491 dst_panel.description = BLI_strdup_null(src_panel.description);
492 dst_panel.identifier = generate_uid ? generate_uid() : src_panel.identifier;
493
494 panel_init(dst_panel, src_panel.items(), flag, generate_uid);
495 break;
496 }
497 }
498}
499
500static void item_free(bNodeTreeInterfaceItem &item, const bool do_id_user)
501{
502 switch (item.item_type) {
504 bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
505
506 if (socket.socket_data != nullptr) {
507 socket_types::socket_data_free(socket, do_id_user);
509 }
510
511 MEM_SAFE_FREE(socket.name);
516 if (socket.properties) {
517 IDP_FreePropertyContent_ex(socket.properties, do_id_user);
518 MEM_freeN(socket.properties);
519 }
520 break;
521 }
523 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
524
525 panel.clear(do_id_user);
526 MEM_SAFE_FREE(panel.name);
528 break;
529 }
530 }
531
532 MEM_freeN(&item);
533}
534
536
538{
539 switch (item.item_type) {
541 bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
542 BLO_write_string(writer, socket.name);
543 BLO_write_string(writer, socket.identifier);
544 BLO_write_string(writer, socket.description);
545 BLO_write_string(writer, socket.socket_type);
547 if (socket.properties) {
548 IDP_BlendWrite(writer, socket.properties);
549 }
550
551 socket_types::socket_data_write(writer, socket);
552 break;
553 }
555 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
556 BLO_write_string(writer, panel.name);
557 BLO_write_string(writer, panel.description);
558 BLO_write_pointer_array(writer, panel.items_num, panel.items_array);
559 for (bNodeTreeInterfaceItem *child_item : panel.items()) {
560 item_write_struct(writer, *child_item);
561 }
562 break;
563 }
564 }
565}
566
568{
569 switch (item.item_type) {
572 break;
573 }
576 break;
577 }
578 }
579
580 item_write_data(writer, item);
581}
582
584{
585 switch (item.item_type) {
587 bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
588 BLO_read_string(reader, &socket.name);
589 BLO_read_string(reader, &socket.description);
590 BLO_read_string(reader, &socket.socket_type);
592 BLO_read_string(reader, &socket.identifier);
593 BLO_read_struct(reader, IDProperty, &socket.properties);
594 IDP_BlendDataRead(reader, &socket.properties);
595
597 break;
598 }
600 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
601 BLO_read_string(reader, &panel.name);
602 BLO_read_string(reader, &panel.description);
604 reader, panel.items_num, reinterpret_cast<void **>(&panel.items_array));
605 for (const int i : blender::IndexRange(panel.items_num)) {
606 BLO_read_struct(reader, NodeEnumItem, &panel.items_array[i]);
607 item_read_data(reader, *panel.items_array[i]);
608 }
609 break;
610 }
611 }
612}
613
615{
616 switch (item.item_type) {
618 bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
619
622 BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data);
623 }));
624
626 break;
627 }
629 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
630 for (bNodeTreeInterfaceItem *item : panel.items()) {
631 item_foreach_id(data, *item);
632 }
633 break;
634 }
635 }
636}
637
638/* Move all child items to the new parent. */
640{
641 switch (item.item_type) {
643 return {};
644 }
646 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
647 return panel.items();
648 }
649 }
650 return {};
651}
652
653} // namespace item_types
654
655} // namespace blender::bke::node_interface
656
657using namespace blender::bke::node_interface;
658
659blender::bke::bNodeSocketType *bNodeTreeInterfaceSocket::socket_typeinfo() const
660{
662}
663
664blender::ColorGeometry4f bNodeTreeInterfaceSocket::socket_color() const
665{
666 blender::bke::bNodeSocketType *typeinfo = this->socket_typeinfo();
667 if (typeinfo && typeinfo->draw_color_simple) {
668 float color[4];
669 typeinfo->draw_color_simple(typeinfo, color);
671 }
672 else {
673 return blender::ColorGeometry4f(1.0f, 0.0f, 1.0f, 1.0f);
674 }
675}
676
677bool bNodeTreeInterfaceSocket::set_socket_type(const char *new_socket_type)
678{
679 const char *idname = socket_types::try_get_supported_socket_type(new_socket_type);
680 if (idname == nullptr) {
681 return false;
682 }
683
684 if (this->socket_data != nullptr) {
687 }
689
690 this->socket_type = BLI_strdup(new_socket_type);
691 this->socket_data = socket_types::make_socket_data(new_socket_type);
692
693 return true;
694}
695
696void bNodeTreeInterfaceSocket::init_from_socket_instance(const bNodeSocket *socket)
697{
698 const char *idname = socket_types::try_get_supported_socket_type(socket->idname);
699 BLI_assert(idname != nullptr);
700
701 if (this->socket_data != nullptr) {
704 }
706 if (socket->flag & SOCK_HIDE_VALUE) {
708 }
709
710 this->socket_type = BLI_strdup(idname);
713}
714
715blender::IndexRange bNodeTreeInterfacePanel::items_range() const
716{
717 return blender::IndexRange(items_num);
718}
719
720blender::Span<const bNodeTreeInterfaceItem *> bNodeTreeInterfacePanel::items() const
721{
722 return blender::Span(items_array, items_num);
723}
724
725blender::MutableSpan<bNodeTreeInterfaceItem *> bNodeTreeInterfacePanel::items()
726{
727 return blender::MutableSpan(items_array, items_num);
728}
729
730bool bNodeTreeInterfacePanel::contains(const bNodeTreeInterfaceItem &item) const
731{
732 return items().contains(&item);
733}
734
735bool bNodeTreeInterfacePanel::contains_recursive(const bNodeTreeInterfaceItem &item) const
736{
737 bool is_child = false;
738 /* Have to capture item address here instead of just a reference,
739 * otherwise pointer comparison will not work. */
740 this->foreach_item(
741 [&](const bNodeTreeInterfaceItem &titem) {
742 if (&titem == &item) {
743 is_child = true;
744 return false;
745 }
746 return true;
747 },
748 true);
749 return is_child;
750}
751
752int bNodeTreeInterfacePanel::item_position(const bNodeTreeInterfaceItem &item) const
753{
754 return items().first_index_try(&item);
755}
756
757int bNodeTreeInterfacePanel::item_index(const bNodeTreeInterfaceItem &item) const
758{
759 int index = 0;
760 bool found = false;
761 /* Have to capture item address here instead of just a reference,
762 * otherwise pointer comparison will not work. */
763 this->foreach_item([&](const bNodeTreeInterfaceItem &titem) {
764 if (&titem == &item) {
765 found = true;
766 return false;
767 }
768 ++index;
769 return true;
770 });
771 return found ? index : -1;
772}
773
774const bNodeTreeInterfaceItem *bNodeTreeInterfacePanel::item_at_index(int index) const
775{
776 int i = 0;
777 const bNodeTreeInterfaceItem *result = nullptr;
778 this->foreach_item([&](const bNodeTreeInterfaceItem &item) {
779 if (i == index) {
780 result = &item;
781 return false;
782 }
783 ++i;
784 return true;
785 });
786 return result;
787}
788
789bNodeTreeInterfacePanel *bNodeTreeInterfacePanel::find_parent_recursive(
790 const bNodeTreeInterfaceItem &item)
791{
792 std::queue<bNodeTreeInterfacePanel *> queue;
793
794 if (this->contains(item)) {
795 return this;
796 }
797 queue.push(this);
798
799 while (!queue.empty()) {
800 bNodeTreeInterfacePanel *parent = queue.front();
801 queue.pop();
802
803 for (bNodeTreeInterfaceItem *titem : parent->items()) {
804 if (titem->item_type != NODE_INTERFACE_PANEL) {
805 continue;
806 }
807
809 if (tpanel->contains(item)) {
810 return tpanel;
811 }
812 queue.push(tpanel);
813 }
814 }
815
816 return nullptr;
817}
818
819int bNodeTreeInterfacePanel::find_valid_insert_position_for_item(
820 const bNodeTreeInterfaceItem &item, const int initial_pos) const
821{
822 const bool sockets_above_panels = !(this->flag &
824 const blender::Span<const bNodeTreeInterfaceItem *> items = this->items();
825
826 /* True if item a should be above item b. */
827 auto item_compare = [sockets_above_panels](const bNodeTreeInterfaceItem &a,
828 const bNodeTreeInterfaceItem &b) -> bool {
829 if (a.item_type != b.item_type) {
830 /* Keep sockets above panels. */
831 if (sockets_above_panels) {
833 }
834 }
835 else {
836 /* Keep outputs above inputs. */
838 const bNodeTreeInterfaceSocket &sa = reinterpret_cast<const bNodeTreeInterfaceSocket &>(a);
839 const bNodeTreeInterfaceSocket &sb = reinterpret_cast<const bNodeTreeInterfaceSocket &>(b);
840 const bool is_output_a = sa.flag & NODE_INTERFACE_SOCKET_OUTPUT;
841 const bool is_output_b = sb.flag & NODE_INTERFACE_SOCKET_OUTPUT;
842 if (is_output_a != is_output_b) {
843 return is_output_a;
844 }
845 }
846 }
847 return false;
848 };
849
850 if (items.is_empty()) {
851 return initial_pos;
852 }
853
854 /* Insertion sort for a single item.
855 * items.size() is a valid position for appending. */
856 int test_pos = clamp_i(initial_pos, 0, items.size());
857 /* Move upward until valid position found. */
858 while (test_pos > 0 && item_compare(item, *items[test_pos - 1])) {
859 --test_pos;
860 }
861 /* Move downward until valid position found.
862 * Result can be out of range, this is valid, items get appended. */
863 while (test_pos < items.size() && item_compare(*items[test_pos], item)) {
864 ++test_pos;
865 }
866 return test_pos;
867}
868
869void bNodeTreeInterfacePanel::add_item(bNodeTreeInterfaceItem &item)
870{
871 /* Same as inserting at the end. */
872 insert_item(item, this->items_num);
873}
874
875void bNodeTreeInterfacePanel::insert_item(bNodeTreeInterfaceItem &item, int position)
876{
877 /* Are child panels allowed? */
878 BLI_assert(item.item_type != NODE_INTERFACE_PANEL ||
880
881 /* Apply any constraints on the item positions. */
882 position = find_valid_insert_position_for_item(item, position);
883 position = std::min(std::max(position, 0), items_num);
884
885 blender::MutableSpan<bNodeTreeInterfaceItem *> old_items = this->items();
886 items_num++;
887 items_array = MEM_cnew_array<bNodeTreeInterfaceItem *>(items_num, __func__);
888 this->items().take_front(position).copy_from(old_items.take_front(position));
889 this->items().drop_front(position + 1).copy_from(old_items.drop_front(position));
890 this->items()[position] = &item;
891
892 if (old_items.data()) {
893 MEM_freeN(old_items.data());
894 }
895}
896
897bool bNodeTreeInterfacePanel::remove_item(bNodeTreeInterfaceItem &item, const bool free)
898{
899 const int position = this->item_position(item);
900 if (!this->items().index_range().contains(position)) {
901 return false;
902 }
903
904 blender::MutableSpan<bNodeTreeInterfaceItem *> old_items = this->items();
905 items_num--;
906 items_array = MEM_cnew_array<bNodeTreeInterfaceItem *>(items_num, __func__);
907 this->items().take_front(position).copy_from(old_items.take_front(position));
908 this->items().drop_front(position).copy_from(old_items.drop_front(position + 1));
909
910 /* Guaranteed not empty, contains at least the removed item */
911 MEM_freeN(old_items.data());
912
913 if (free) {
915 }
916
917 return true;
918}
919
920void bNodeTreeInterfacePanel::clear(bool do_id_user)
921{
922 for (bNodeTreeInterfaceItem *item : this->items()) {
923 item_types::item_free(*item, do_id_user);
924 }
926 items_array = nullptr;
927 items_num = 0;
928}
929
930bool bNodeTreeInterfacePanel::move_item(bNodeTreeInterfaceItem &item, int new_position)
931{
932 const int old_position = this->item_position(item);
933 if (!this->items().index_range().contains(old_position)) {
934 return false;
935 }
936 if (old_position == new_position) {
937 /* Nothing changes. */
938 return true;
939 }
940
941 new_position = find_valid_insert_position_for_item(item, new_position);
942 new_position = std::min(std::max(new_position, 0), items_num);
943
944 if (old_position < new_position) {
945 /* Actual target position and all existing items shifted by 1. */
946 const blender::Span<bNodeTreeInterfaceItem *> moved_items = this->items().slice(
947 old_position + 1, new_position - old_position - 1);
948 bNodeTreeInterfaceItem *tmp = this->items()[old_position];
949 std::copy(
950 moved_items.begin(), moved_items.end(), this->items().drop_front(old_position).data());
951 this->items()[new_position - 1] = tmp;
952 }
953 else /* old_position > new_position */ {
954 const blender::Span<bNodeTreeInterfaceItem *> moved_items = this->items().slice(
955 new_position, old_position - new_position);
956 bNodeTreeInterfaceItem *tmp = this->items()[old_position];
957 std::copy_backward(
958 moved_items.begin(), moved_items.end(), this->items().drop_front(old_position + 1).data());
959 this->items()[new_position] = tmp;
960 }
961
962 return true;
963}
964
965void bNodeTreeInterfacePanel::foreach_item(
966 blender::FunctionRef<bool(bNodeTreeInterfaceItem &item)> fn, bool include_self)
967{
968 using ItemSpan = blender::Span<bNodeTreeInterfaceItem *>;
969 blender::Stack<ItemSpan> stack;
970
971 if (include_self && fn(this->item) == false) {
972 return;
973 }
974 stack.push(this->items());
975
976 while (!stack.is_empty()) {
977 const ItemSpan current_items = stack.pop();
978
979 for (const int index : current_items.index_range()) {
980 bNodeTreeInterfaceItem *item = current_items[index];
981 if (fn(*item) == false) {
982 return;
983 }
984
985 if (item->item_type == NODE_INTERFACE_PANEL) {
986 bNodeTreeInterfacePanel *panel = reinterpret_cast<bNodeTreeInterfacePanel *>(item);
987 /* Reinsert remaining items. */
988 if (index < current_items.size() - 1) {
989 const ItemSpan remaining_items = current_items.drop_front(index + 1);
990 stack.push(remaining_items);
991 }
992 /* Handle child items first before continuing with current span. */
993 stack.push(panel->items());
994 break;
995 }
996 }
997 }
998}
999
1000void bNodeTreeInterfacePanel::foreach_item(
1001 blender::FunctionRef<bool(const bNodeTreeInterfaceItem &item)> fn, bool include_self) const
1002{
1003 using ItemSpan = blender::Span<const bNodeTreeInterfaceItem *>;
1004 blender::Stack<ItemSpan> stack;
1005
1006 if (include_self && fn(this->item) == false) {
1007 return;
1008 }
1009 stack.push(this->items());
1010
1011 while (!stack.is_empty()) {
1012 const ItemSpan current_items = stack.pop();
1013
1014 for (const int index : current_items.index_range()) {
1015 const bNodeTreeInterfaceItem *item = current_items[index];
1016 if (fn(*item) == false) {
1017 return;
1018 }
1019
1020 if (item->item_type == NODE_INTERFACE_PANEL) {
1021 const bNodeTreeInterfacePanel *panel = reinterpret_cast<const bNodeTreeInterfacePanel *>(
1022 item);
1023 /* Reinsert remaining items. */
1024 if (index < current_items.size() - 1) {
1025 const ItemSpan remaining_items = current_items.drop_front(index + 1);
1026 stack.push(remaining_items);
1027 }
1028 /* Handle child items first before continuing with current span. */
1029 stack.push(panel->items());
1030 break;
1031 }
1032 }
1033 }
1034}
1035
1037
1039 const StringRef name,
1040 const StringRef description,
1041 const StringRef socket_type,
1043{
1044 BLI_assert(!socket_type.is_empty());
1045
1046 const char *idname = socket_types::try_get_supported_socket_type(socket_type);
1047 if (idname == nullptr) {
1048 return nullptr;
1049 }
1050
1051 bNodeTreeInterfaceSocket *new_socket = MEM_cnew<bNodeTreeInterfaceSocket>(__func__);
1052 BLI_assert(new_socket);
1053
1054 /* Init common socket properties. */
1055 new_socket->identifier = BLI_sprintfN("Socket_%d", uid);
1056 new_socket->item.item_type = NODE_INTERFACE_SOCKET;
1057 new_socket->name = BLI_strdupn(name.data(), name.size());
1058 new_socket->description = description.is_empty() ?
1059 nullptr :
1060 BLI_strdupn(description.data(), description.size());
1061 new_socket->socket_type = BLI_strdupn(socket_type.data(), socket_type.size());
1062 new_socket->flag = flag;
1063
1064 new_socket->socket_data = socket_types::make_socket_data(socket_type);
1065
1066 return new_socket;
1067}
1068
1070 const bNode &from_node,
1071 const bNodeSocket &from_sock,
1072 const StringRef socket_type,
1073 const StringRef name)
1074{
1078
1079 bNodeTreeInterfaceSocket *iosock = ntree.tree_interface.add_socket(
1080 name, from_sock.description, socket_type, flag, nullptr);
1081 if (iosock == nullptr) {
1082 return nullptr;
1083 }
1084 const blender::bke::bNodeSocketType *typeinfo = iosock->socket_typeinfo();
1085 if (typeinfo->interface_from_socket) {
1086 typeinfo->interface_from_socket(&ntree.id, iosock, &from_node, &from_sock);
1087 UNUSED_VARS(from_sock);
1088 }
1089 return iosock;
1090}
1091
1093 const blender::StringRef name,
1094 const blender::StringRef description,
1096{
1097 BLI_assert(!name.is_empty());
1098
1099 bNodeTreeInterfacePanel *new_panel = MEM_cnew<bNodeTreeInterfacePanel>(__func__);
1100 new_panel->item.item_type = NODE_INTERFACE_PANEL;
1101 new_panel->name = BLI_strdupn(name.data(), name.size());
1102 new_panel->description = description.is_empty() ?
1103 nullptr :
1104 BLI_strdupn(description.data(), description.size());
1105 new_panel->identifier = uid;
1106 new_panel->flag = flag;
1107 return new_panel;
1108}
1109
1110} // namespace blender::bke::node_interface
1111
1112void bNodeTreeInterface::init_data()
1113{
1114 this->runtime = MEM_new<blender::bke::bNodeTreeInterfaceRuntime>(__func__);
1115 this->tag_missing_runtime_data();
1116
1117 /* Root panel is allowed to contain child panels. */
1119}
1120
1121void bNodeTreeInterface::copy_data(const bNodeTreeInterface &src, int flag)
1122{
1123 item_types::panel_init(this->root_panel, src.root_panel.items(), flag, nullptr);
1124 this->active_index = src.active_index;
1125
1126 this->runtime = MEM_new<blender::bke::bNodeTreeInterfaceRuntime>(__func__);
1127 this->tag_missing_runtime_data();
1128}
1129
1130void bNodeTreeInterface::free_data()
1131{
1132 MEM_delete(this->runtime);
1133
1134 /* Called when freeing the main database, don't do user refcount here. */
1135 this->root_panel.clear(false);
1136}
1137
1138void bNodeTreeInterface::write(BlendWriter *writer)
1139{
1140 /* Don't write the root panel struct itself, it's nested in the interface struct. */
1141 item_types::item_write_data(writer, this->root_panel.item);
1142}
1143
1144void bNodeTreeInterface::read_data(BlendDataReader *reader)
1145{
1146 item_types::item_read_data(reader, this->root_panel.item);
1147
1148 this->runtime = MEM_new<blender::bke::bNodeTreeInterfaceRuntime>(__func__);
1149 this->tag_missing_runtime_data();
1150}
1151
1152bNodeTreeInterfaceItem *bNodeTreeInterface::active_item()
1153{
1154 bNodeTreeInterfaceItem *active = nullptr;
1155 int count = active_index;
1156 this->foreach_item([&](bNodeTreeInterfaceItem &item) {
1157 if (count == 0) {
1158 active = &item;
1159 return false;
1160 }
1161 --count;
1162 return true;
1163 });
1164 return active;
1165}
1166
1167const bNodeTreeInterfaceItem *bNodeTreeInterface::active_item() const
1168{
1169 const bNodeTreeInterfaceItem *active = nullptr;
1170 int count = active_index;
1171 this->foreach_item([&](const bNodeTreeInterfaceItem &item) {
1172 if (count == 0) {
1173 active = &item;
1174 return false;
1175 }
1176 --count;
1177 return true;
1178 });
1179 return active;
1180}
1181
1182void bNodeTreeInterface::active_item_set(bNodeTreeInterfaceItem *item)
1183{
1184 active_index = 0;
1185 int count = 0;
1186 this->foreach_item([&](bNodeTreeInterfaceItem &titem) {
1187 if (&titem == item) {
1189 return false;
1190 }
1191 ++count;
1192 return true;
1193 });
1194}
1195
1196bNodeTreeInterfaceSocket *bNodeTreeInterface::add_socket(const blender::StringRef name,
1197 const blender::StringRef description,
1198 const blender::StringRef socket_type,
1201{
1202 /* Check that each interface socket is either an input or an output. Technically, it can be both
1203 * at the same time, but we don't want that for the time being. */
1206 if (parent == nullptr) {
1207 parent = &root_panel;
1208 }
1209 BLI_assert(this->find_item(parent->item));
1210
1212 next_uid++, name, description, socket_type, flag);
1213 if (new_socket) {
1214 parent->add_item(new_socket->item);
1215 }
1216
1217 this->tag_items_changed();
1218 return new_socket;
1219}
1220
1221bNodeTreeInterfaceSocket *bNodeTreeInterface::insert_socket(const blender::StringRef name,
1222 const blender::StringRef description,
1223 const blender::StringRef socket_type,
1226 const int position)
1227{
1228 if (parent == nullptr) {
1229 parent = &root_panel;
1230 }
1231 BLI_assert(this->find_item(parent->item));
1232
1234 next_uid++, name, description, socket_type, flag);
1235 if (new_socket) {
1236 parent->insert_item(new_socket->item, position);
1237 }
1238
1239 this->tag_items_changed();
1240 return new_socket;
1241}
1242
1243bNodeTreeInterfacePanel *bNodeTreeInterface::add_panel(const blender::StringRef name,
1244 const blender::StringRef description,
1247{
1248 if (parent == nullptr) {
1249 parent = &root_panel;
1250 }
1251 BLI_assert(this->find_item(parent->item));
1252
1254 /* Parent does not allow adding child panels. */
1255 return nullptr;
1256 }
1257
1258 bNodeTreeInterfacePanel *new_panel = make_panel(next_uid++, name, description, flag);
1259 if (new_panel) {
1260 parent->add_item(new_panel->item);
1261 }
1262
1263 this->tag_items_changed();
1264 return new_panel;
1265}
1266
1267bNodeTreeInterfacePanel *bNodeTreeInterface::insert_panel(const blender::StringRef name,
1268 const blender::StringRef description,
1271 const int position)
1272{
1273 if (parent == nullptr) {
1274 parent = &root_panel;
1275 }
1276 BLI_assert(this->find_item(parent->item));
1277
1279 /* Parent does not allow adding child panels. */
1280 return nullptr;
1281 }
1282
1283 bNodeTreeInterfacePanel *new_panel = make_panel(next_uid++, name, description, flag);
1284 if (new_panel) {
1285 parent->insert_item(new_panel->item, position);
1286 }
1287
1288 this->tag_items_changed();
1289 return new_panel;
1290}
1291
1292bNodeTreeInterfaceItem *bNodeTreeInterface::add_item_copy(const bNodeTreeInterfaceItem &item,
1294{
1295 if (parent == nullptr) {
1296 parent = &root_panel;
1297 }
1298 BLI_assert(this->find_item(item));
1299 BLI_assert(this->find_item(parent->item));
1300
1301 if (item.item_type == NODE_INTERFACE_PANEL &&
1303 {
1304 /* Parent does not allow adding child panels. */
1305 return nullptr;
1306 }
1307
1308 bNodeTreeInterfaceItem *citem = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(&item));
1309 item_types::item_copy(*citem, item, 0, [&]() { return this->next_uid++; });
1310 parent->add_item(*citem);
1311
1312 this->tag_items_changed();
1313 return citem;
1314}
1315
1316bNodeTreeInterfaceItem *bNodeTreeInterface::insert_item_copy(const bNodeTreeInterfaceItem &item,
1318 int position)
1319{
1320 if (parent == nullptr) {
1321 parent = &root_panel;
1322 }
1323 BLI_assert(this->find_item(item));
1324 BLI_assert(this->find_item(parent->item));
1325
1326 if (item.item_type == NODE_INTERFACE_PANEL &&
1328 {
1329 /* Parent does not allow adding child panels. */
1330 return nullptr;
1331 }
1332
1333 bNodeTreeInterfaceItem *citem = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(&item));
1334 item_types::item_copy(*citem, item, 0, [&]() { return this->next_uid++; });
1335 parent->insert_item(*citem, position);
1336
1337 this->tag_items_changed();
1338 return citem;
1339}
1340
1341bool bNodeTreeInterface::remove_item(bNodeTreeInterfaceItem &item, bool move_content_to_parent)
1342{
1343 bNodeTreeInterfacePanel *parent = this->find_item_parent(item, true);
1344 if (parent == nullptr) {
1345 return false;
1346 }
1347 if (move_content_to_parent) {
1348 int position = parent->item_position(item);
1349 /* Cache children to avoid invalidating the iterator. */
1350 blender::Array<bNodeTreeInterfaceItem *> children(item_types::item_children(item));
1351 for (bNodeTreeInterfaceItem *child : children) {
1352 this->move_item_to_parent(*child, parent, position++);
1353 }
1354 }
1355 if (parent->remove_item(item, true)) {
1356 this->tag_items_changed();
1357 return true;
1358 }
1359
1360 return false;
1361}
1362
1363void bNodeTreeInterface::clear_items()
1364{
1365 root_panel.clear(true);
1366 this->tag_items_changed();
1367}
1368
1369bool bNodeTreeInterface::move_item(bNodeTreeInterfaceItem &item, const int new_position)
1370{
1371 bNodeTreeInterfacePanel *parent = this->find_item_parent(item, true);
1372 if (parent == nullptr) {
1373 return false;
1374 }
1375
1376 if (parent->move_item(item, new_position)) {
1377 this->tag_items_changed();
1378 return true;
1379 }
1380 return false;
1381}
1382
1383bool bNodeTreeInterface::move_item_to_parent(bNodeTreeInterfaceItem &item,
1384 bNodeTreeInterfacePanel *new_parent,
1385 int new_position)
1386{
1387 if (new_parent == nullptr) {
1388 new_parent = &this->root_panel;
1389 }
1390 bNodeTreeInterfacePanel *parent = this->find_item_parent(item, true);
1391 if (parent == nullptr) {
1392 return false;
1393 }
1394 if (item.item_type == NODE_INTERFACE_PANEL && new_parent &&
1396 {
1397 /* Parent does not allow adding child panels. */
1398 return false;
1399 }
1400 if (parent == new_parent) {
1401 if (parent->move_item(item, new_position)) {
1402 this->tag_items_changed();
1403 return true;
1404 }
1405 }
1406 else {
1407 /* NOTE: only remove and reinsert when parents different, otherwise removing the item can
1408 * change the desired target position! */
1409 if (parent->remove_item(item, false)) {
1410 new_parent->insert_item(item, new_position);
1411 this->tag_items_changed();
1412 return true;
1413 }
1414 }
1415 return false;
1416}
1417
1418void bNodeTreeInterface::foreach_id(LibraryForeachIDData *cb)
1419{
1421}
1422
1423bool bNodeTreeInterface::items_cache_is_available() const
1424{
1425 return !this->runtime->items_cache_mutex_.is_dirty();
1426}
1427
1428void bNodeTreeInterface::ensure_items_cache() const
1429{
1430 blender::bke::bNodeTreeInterfaceRuntime &runtime = *this->runtime;
1431
1432 runtime.items_cache_mutex_.ensure([&]() {
1433 /* Rebuild draw-order list of interface items for linear access. */
1434 runtime.items_.clear();
1435 runtime.inputs_.clear();
1436 runtime.outputs_.clear();
1437
1438 /* Items in the cache are mutable pointers, but node tree update considers ID data to be
1439 * immutable when caching. DNA ListBase pointers can be mutable even if their container is
1440 * const, but the items returned by #foreach_item inherit qualifiers from the container. */
1441 bNodeTreeInterface &mutable_self = const_cast<bNodeTreeInterface &>(*this);
1442
1443 mutable_self.foreach_item([&](bNodeTreeInterfaceItem &item) {
1444 runtime.items_.append(&item);
1446 if (socket->flag & NODE_INTERFACE_SOCKET_INPUT) {
1447 runtime.inputs_.append(socket);
1448 }
1449 if (socket->flag & NODE_INTERFACE_SOCKET_OUTPUT) {
1450 runtime.outputs_.append(socket);
1451 }
1452 }
1453 return true;
1454 });
1455 });
1456}
1457
1458void bNodeTreeInterface::tag_missing_runtime_data()
1459{
1460 this->runtime->changed_flag_ |= NODE_INTERFACE_CHANGED_ALL;
1461 this->runtime->items_cache_mutex_.tag_dirty();
1462}
1463
1464bool bNodeTreeInterface::is_changed() const
1465{
1466 return this->runtime->changed_flag_ != NODE_INTERFACE_CHANGED_NOTHING;
1467}
1468
1469void bNodeTreeInterface::tag_items_changed()
1470{
1471 this->runtime->changed_flag_ |= NODE_INTERFACE_CHANGED_ITEMS;
1472 this->runtime->items_cache_mutex_.tag_dirty();
1473}
1474
1475void bNodeTreeInterface::reset_changed_flags()
1476{
1477 this->runtime->changed_flag_ = NODE_INTERFACE_CHANGED_NOTHING;
1478}
void IDP_foreach_property(IDProperty *id_property_root, int type_filter, blender::FunctionRef< void(IDProperty *id_property)> callback)
#define IDP_BlendDataRead(reader, prop)
void IDP_FreePropertyContent_ex(IDProperty *prop, bool do_id_user)
Definition idprop.cc:1189
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:843
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1437
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
@ LIB_ID_CREATE_NO_USER_REFCOUNT
#define BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data_, func_call_)
@ IDWALK_CB_USER
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_kdtree_nd_ free(KDTree *tree)
MINLINE int clamp_i(int value, int min, int max)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:29
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.c:45
#define UNUSED_VARS(...)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define BLO_read_data_address(reader, ptr_p)
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
void BLO_read_pointer_array(BlendDataReader *reader, int array_size, void **ptr_p)
Definition readfile.cc:5052
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
@ IDP_TYPE_FILTER_ID
Object groups, one object can be in many groups at once.
@ NODE_INTERFACE_PANEL_ALLOW_CHILD_PANELS
@ NODE_INTERFACE_PANEL_ALLOW_SOCKETS_AFTER_PANELS
@ NODE_INTERFACE_SOCKET_HIDE_VALUE
struct bNodeTreeInterface bNodeTreeInterface
struct bNodeTreeInterfaceSocket bNodeTreeInterfaceSocket
struct bNodeTreeInterfacePanel bNodeTreeInterfacePanel
struct bNodeTreeInterfaceItem bNodeTreeInterfaceItem
@ SOCK_OUT
@ SOCK_IN
@ SOCK_HIDE_VALUE
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
@ PROP_NONE
Definition RNA_types.hh:136
constexpr T * data() const
Definition BLI_span.hh:540
constexpr MutableSpan drop_front(const int64_t n) const
Definition BLI_span.hh:608
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:630
constexpr Span drop_front(int64_t n) const
Definition BLI_span.hh:172
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr const T * end() const
Definition BLI_span.hh:225
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr const T * begin() const
Definition BLI_span.hh:221
constexpr Span take_front(int64_t n) const
Definition BLI_span.hh:194
constexpr bool is_empty() const
Definition BLI_span.hh:261
bool is_empty() const
Definition BLI_stack.hh:308
void push(const T &value)
Definition BLI_stack.hh:213
constexpr bool is_empty() const
constexpr int64_t size() const
constexpr const char * data() const
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
int count
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
void item_write_struct(BlendWriter *writer, bNodeTreeInterfaceItem &item)
static void item_copy(bNodeTreeInterfaceItem &dst, const bNodeTreeInterfaceItem &src, int flag, UidGeneratorFn generate_uid)
static void item_free(bNodeTreeInterfaceItem &item, const bool do_id_user)
static void item_write_data(BlendWriter *writer, bNodeTreeInterfaceItem &item)
static Span< bNodeTreeInterfaceItem * > item_children(bNodeTreeInterfaceItem &item)
static void item_read_data(BlendDataReader *reader, bNodeTreeInterfaceItem &item)
static void item_foreach_id(LibraryForeachIDData *data, bNodeTreeInterfaceItem &item)
static void panel_init(bNodeTreeInterfacePanel &panel, const Span< const bNodeTreeInterfaceItem * > items_src, const int flag, UidGeneratorFn generate_uid)
static void socket_data_read_data(BlendDataReader *reader, bNodeTreeInterfaceSocket &socket)
void socket_data_foreach_id_impl(LibraryForeachIDData *, T &)
static void * make_socket_data(const StringRef socket_type)
static const char * try_get_supported_socket_type(const StringRef socket_type)
static void socket_data_free(bNodeTreeInterfaceSocket &socket, const bool do_id_user)
void socket_data_to_static_type_tag(const StringRef socket_type, const Fn &fn)
static void socket_data_write(BlendWriter *writer, bNodeTreeInterfaceSocket &socket)
static void socket_data_foreach_id(LibraryForeachIDData *data, bNodeTreeInterfaceSocket &socket)
static void socket_data_copy(bNodeTreeInterfaceSocket &dst, const bNodeTreeInterfaceSocket &src, int flag)
static void socket_data_copy_ptr(bNodeTreeInterfaceSocket &dst, const void *src_socket_data, int flag)
void socket_data_write_impl(BlendWriter *writer, bNodeSocketValueFloat &data)
void socket_data_read_data_impl(BlendDataReader *reader, T **data)
T & get_item_as(bNodeTreeInterfaceItem &item)
static bNodeTreeInterfaceSocket * make_socket(const int uid, const StringRef name, const StringRef description, const StringRef socket_type, const NodeTreeInterfaceSocketFlag flag)
static bNodeTreeInterfacePanel * make_panel(const int uid, const blender::StringRef name, const blender::StringRef description, const NodeTreeInterfacePanelFlag flag)
T & get_socket_data_as(bNodeTreeInterfaceSocket &item)
bNodeTreeInterfaceSocket * add_interface_socket_from_node(bNodeTree &ntree, const bNode &from_node, const bNodeSocket &from_sock, const StringRef socket_type, const StringRef name)
bool node_is_static_socket_type(const bNodeSocketType *stype)
Definition node.cc:2117
bNodeSocketType * node_socket_type_find(const char *idname)
Definition node.cc:1763
const char * node_static_socket_type(int type, int subtype)
Definition node.cc:2126
ThreadQueue * queue
all scheduled work for the cpu
void index(const bNode &, void *r_value)
void position(const bNode &, void *r_value)
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
NodeTreeInterfaceChangedFlag
@ NODE_INTERFACE_CHANGED_ALL
@ NODE_INTERFACE_CHANGED_ITEMS
@ NODE_INTERFACE_CHANGED_NOTHING
static bool is_child(const Object *ob, const Object *parent)
#define FLT_MAX
Definition stdcycles.h:14
Definition DNA_ID.h:413
const RuntimeNodeEnumItemsHandle * enum_items
char description[64]
void * default_value
char idname[64]
bNodeTreeInterfaceItem ** items_array
bNodeTreeInterfacePanel root_panel
bNodeTreeInterfaceRuntimeHandle * runtime
bNodeTreeInterface tree_interface
Defines a socket type.
Definition BKE_node.hh:151
void(* draw_color_simple)(const bNodeSocketType *socket_type, float *r_color)
Definition BKE_node.hh:162
void(* interface_from_socket)(ID *id, bNodeTreeInterfaceSocket *interface_socket, const bNode *node, const bNodeSocket *socket)
Definition BKE_node.hh:170
uint8_t flag
Definition wm_window.cc:138