Blender V4.5
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 <queue>
6
7#include "BKE_idprop.hh"
8#include "BKE_lib_id.hh"
9#include "BKE_lib_query.hh"
10#include "BKE_node.hh"
11#include "BKE_node_enum.hh"
12#include "BKE_node_runtime.hh"
14
15#include "BLI_math_vector.h"
16#include "BLI_stack.hh"
17#include "BLI_string.h"
18
19#include "BLO_read_write.hh"
20
22#include "DNA_material_types.h"
24#include "DNA_node_types.h"
25
27
29
31
32namespace socket_types {
33
34/* Try to get a supported socket type from some final type.
35 * Built-in socket can have multiple registered RNA types for the base type, e.g.
36 * `NodeSocketFloatUnsigned`, `NodeSocketFloatFactor`. Only the "base type" (`NodeSocketFloat`)
37 * is considered valid for interface sockets.
38 */
39static std::optional<StringRef> try_get_supported_socket_type(const StringRef socket_type)
40{
41 const blender::bke::bNodeSocketType *typeinfo = bke::node_socket_type_find(socket_type);
42 if (typeinfo == nullptr) {
43 return std::nullopt;
44 }
45 /* For builtin socket types only the base type is supported. */
46 if (node_is_static_socket_type(*typeinfo)) {
47 if (const std::optional<StringRefNull> type_name = bke::node_static_socket_type(typeinfo->type,
48 PROP_NONE))
49 {
50 return *type_name;
51 }
52 return std::nullopt;
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 data.dimensions = 3;
142 copy_v3_v3(data.value, default_value);
143 data.min = -FLT_MAX;
144 data.max = FLT_MAX;
145}
147{
148 static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f};
149 copy_v4_v4(data.value, default_value);
150}
152{
153 data.subtype = PROP_NONE;
154 data.value[0] = '\0';
155}
157{
158 data.value = nullptr;
159}
161{
162 data.value = nullptr;
163}
165{
166 data.value = nullptr;
167}
169{
170 data.value = nullptr;
171}
173{
174 data.value = nullptr;
175}
177{
178 data.value = -1;
179 data.enum_items = nullptr;
180 data.runtime_flag = 0;
181}
182
183static void *make_socket_data(const StringRef socket_type)
184{
185 void *socket_data = nullptr;
186 socket_data_to_static_type_tag(socket_type, [&socket_data](auto type_tag) {
187 using SocketDataType = typename decltype(type_tag)::type;
188 SocketDataType *new_socket_data = MEM_callocN<SocketDataType>(__func__);
189 socket_data_init_impl(*new_socket_data);
190 socket_data = new_socket_data;
191 });
192 return socket_data;
193}
194
196
197/* -------------------------------------------------------------------- */
200
201template<typename T> void socket_data_free_impl(T & /*data*/, const bool /*do_id_user*/) {}
202template<> void socket_data_free_impl(bNodeSocketValueMenu &dst, const bool /*do_id_user*/)
203{
204 if (dst.enum_items) {
205 /* Release shared data pointer. */
206 dst.enum_items->remove_user_and_delete_if_last();
207 }
208}
209
210static void socket_data_free(bNodeTreeInterfaceSocket &socket, const bool do_id_user)
211{
212 socket_data_to_static_type_tag(socket.socket_type, [&](auto type_tag) {
213 using SocketDataType = typename decltype(type_tag)::type;
214 if (do_id_user) {
215 socket_data_id_user_decrement(get_socket_data_as<SocketDataType>(socket));
216 }
218 });
219}
220
222
223/* -------------------------------------------------------------------- */
226
227template<typename T> void socket_data_copy_impl(T & /*dst*/, const T & /*src*/) {}
228template<>
230{
231 /* Copy of shared data pointer. */
232 if (dst.enum_items) {
233 dst.enum_items->add_user();
234 }
235}
236
238 const bNodeTreeInterfaceSocket &src,
239 int flag)
240{
241 socket_data_to_static_type_tag(dst.socket_type, [&](auto type_tag) {
242 using SocketDataType = typename decltype(type_tag)::type;
243 dst.socket_data = MEM_dupallocN(src.socket_data);
244 socket_data_copy_impl(get_socket_data_as<SocketDataType>(dst),
245 get_socket_data_as<SocketDataType>(src));
246 if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
247 socket_data_id_user_increment(get_socket_data_as<SocketDataType>(dst));
248 }
249 });
250}
251
252/* Copy socket data from a raw pointer, e.g. from a #bNodeSocket. */
254 const void *src_socket_data,
255 int flag)
256{
257 socket_data_to_static_type_tag(dst.socket_type, [&](auto type_tag) {
258 using SocketDataType = typename decltype(type_tag)::type;
259
260 if (dst.socket_data != nullptr) {
261 socket_data_free(dst, true);
262 MEM_SAFE_FREE(dst.socket_data);
263 }
264
265 dst.socket_data = MEM_dupallocN(src_socket_data);
267 *static_cast<const SocketDataType *>(src_socket_data));
270 }
271 });
272}
273
275
276/* -------------------------------------------------------------------- */
279
280/* NOTE: no default implementation, every used type must write at least the base struct. */
281
334
336{
337 socket_data_to_static_type_tag(socket.socket_type, [&](auto type_tag) {
338 using SocketDataType = typename decltype(type_tag)::type;
339 socket_data_write_impl(writer, get_socket_data_as<SocketDataType>(socket));
340 });
341}
342
344
345/* -------------------------------------------------------------------- */
348
349template<typename T> void socket_data_read_data_impl(BlendDataReader *reader, T **data)
350{
351 /* FIXME Avoid using low-level untyped read function here. Cannot use the BLO_read_struct
352 * currently (macro expansion would process `T` instead of the actual type). */
354}
356{
357 /* FIXME Avoid using low-level untyped read function here. No type info available here currently.
358 */
360 /* Clear runtime data. */
361 (*data)->enum_items = nullptr;
362 (*data)->runtime_flag = 0;
363}
364
366{
367 bool data_read = false;
368 socket_data_to_static_type_tag(socket.socket_type, [&](auto type_tag) {
369 using SocketDataType = typename decltype(type_tag)::type;
370 socket_data_read_data_impl(reader, reinterpret_cast<SocketDataType **>(&socket.socket_data));
371 data_read = true;
372 });
373 if (!data_read && socket.socket_data) {
374 /* Not sure how this can happen exactly, but it did happen in #127855. */
375 socket.socket_data = nullptr;
376 }
377}
378
380
381/* -------------------------------------------------------------------- */
384
385template<typename T>
387{
388}
397template<>
402template<>
407template<>
412
414{
415 socket_data_to_static_type_tag(socket.socket_type, [&](auto type_tag) {
416 using SocketDataType = typename decltype(type_tag)::type;
417 socket_data_foreach_id_impl(data, get_socket_data_as<SocketDataType>(socket));
418 });
419}
420
422
423} // namespace socket_types
424
425namespace item_types {
426
428
429static void item_copy(bNodeTreeInterfaceItem &dst,
430 const bNodeTreeInterfaceItem &src,
431 int flag,
432 UidGeneratorFn generate_uid);
433
441 const int flag,
442 UidGeneratorFn generate_uid)
443{
444 panel.items_num = items_src.size();
446
447 /* Copy buffers. */
448 for (const int i : items_src.index_range()) {
449 const bNodeTreeInterfaceItem *item_src = items_src[i];
450 panel.items_array[i] = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(item_src));
451 item_types::item_copy(*panel.items_array[i], *item_src, flag, generate_uid);
452 }
453}
454
461 const bNodeTreeInterfaceItem &src,
462 const int flag,
463 UidGeneratorFn generate_uid)
464{
467 bNodeTreeInterfaceSocket &dst_socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(dst);
468 const bNodeTreeInterfaceSocket &src_socket =
469 reinterpret_cast<const bNodeTreeInterfaceSocket &>(src);
470 BLI_assert(src_socket.socket_type != nullptr);
471
472 dst_socket.name = BLI_strdup_null(src_socket.name);
473 dst_socket.description = BLI_strdup_null(src_socket.description);
474 dst_socket.socket_type = BLI_strdup(src_socket.socket_type);
476 dst_socket.identifier = generate_uid ? BLI_sprintfN("Socket_%d", generate_uid()) :
477 BLI_strdup(src_socket.identifier);
478 if (src_socket.properties) {
479 dst_socket.properties = IDP_CopyProperty_ex(src_socket.properties, flag);
480 }
481 if (src_socket.socket_data != nullptr) {
482 socket_types::socket_data_copy(dst_socket, src_socket, flag);
483 }
484 break;
485 }
487 bNodeTreeInterfacePanel &dst_panel = reinterpret_cast<bNodeTreeInterfacePanel &>(dst);
488 const bNodeTreeInterfacePanel &src_panel = reinterpret_cast<const bNodeTreeInterfacePanel &>(
489 src);
490
491 dst_panel.name = BLI_strdup_null(src_panel.name);
492 dst_panel.description = BLI_strdup_null(src_panel.description);
493 dst_panel.identifier = generate_uid ? generate_uid() : src_panel.identifier;
494
495 panel_init(dst_panel, src_panel.items(), flag, generate_uid);
496 break;
497 }
498 }
499}
500
501static void item_free(bNodeTreeInterfaceItem &item, const bool do_id_user)
502{
503 switch (NodeTreeInterfaceItemType(item.item_type)) {
505 bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
506
507 if (socket.socket_data != nullptr) {
508 socket_types::socket_data_free(socket, do_id_user);
510 }
511
512 MEM_SAFE_FREE(socket.name);
517 if (socket.properties) {
518 IDP_FreePropertyContent_ex(socket.properties, do_id_user);
519 MEM_freeN(socket.properties);
520 }
521 break;
522 }
524 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
525
526 panel.clear(do_id_user);
527 MEM_SAFE_FREE(panel.name);
529 break;
530 }
531 }
532
533 MEM_freeN(&item);
534}
535
537
539{
540 switch (NodeTreeInterfaceItemType(item.item_type)) {
542 bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
543 BLO_write_string(writer, socket.name);
544 BLO_write_string(writer, socket.identifier);
545 BLO_write_string(writer, socket.description);
546 BLO_write_string(writer, socket.socket_type);
548 if (socket.properties) {
549 IDP_BlendWrite(writer, socket.properties);
550 }
551
552 socket_types::socket_data_write(writer, socket);
553 break;
554 }
556 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
557 BLO_write_string(writer, panel.name);
558 BLO_write_string(writer, panel.description);
559 BLO_write_pointer_array(writer, panel.items_num, panel.items_array);
560 for (bNodeTreeInterfaceItem *child_item : panel.items()) {
561 item_write_struct(writer, *child_item);
562 }
563 break;
564 }
565 }
566}
567
569{
570 switch (NodeTreeInterfaceItemType(item.item_type)) {
572 /* Forward compatible writing of older single value only flag. To be removed in 5.0. */
577
579 break;
580 }
583 break;
584 }
585 }
586
587 item_write_data(writer, item);
588}
589
591{
592 switch (NodeTreeInterfaceItemType(item.item_type)) {
594 bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
595 BLO_read_string(reader, &socket.name);
596 BLO_read_string(reader, &socket.description);
597 BLO_read_string(reader, &socket.socket_type);
599 BLO_read_string(reader, &socket.identifier);
600 BLO_read_struct(reader, IDProperty, &socket.properties);
601 IDP_BlendDataRead(reader, &socket.properties);
602
603 /* Improve forward compatibility for unknown default input types. */
604 const bNodeSocketType *stype = socket.socket_typeinfo();
606 *stype, NodeDefaultInputType(socket.default_input)))
607 {
609 }
610
612 break;
613 }
615 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
616 BLO_read_string(reader, &panel.name);
617 BLO_read_string(reader, &panel.description);
619 reader, panel.items_num, reinterpret_cast<void **>(&panel.items_array));
620
621 /* Read the direct-data for each interface item if possible. The pointer becomes null if the
622 * struct type is not known. */
623 for (const int i : blender::IndexRange(panel.items_num)) {
625 }
626 /* Forward compatibility: Discard unknown tree interface item types that may be introduced in
627 * the future. Their pointer is set to null above. */
628 panel.items_num = std::remove_if(
629 panel.items_array,
630 panel.items_array + panel.items_num,
631 [&](const bNodeTreeInterfaceItem *item) { return item == nullptr; }) -
632 panel.items_array;
633 /* Now read the actual data if the known interface items. */
634 for (const int i : blender::IndexRange(panel.items_num)) {
635 item_read_data(reader, *panel.items_array[i]);
636 }
637 break;
638 }
639 }
640}
641
643{
644 switch (NodeTreeInterfaceItemType(item.item_type)) {
646 bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
647
650 BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data);
651 }));
652
654 break;
655 }
657 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
658 for (bNodeTreeInterfaceItem *item : panel.items()) {
659 item_foreach_id(data, *item);
660 }
661 break;
662 }
663 }
664}
665
666/* Move all child items to the new parent. */
668{
669 switch (NodeTreeInterfaceItemType(item.item_type)) {
671 return {};
672 }
674 bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
675 return panel.items();
676 }
677 }
678 return {};
679}
680
681} // namespace item_types
682
683} // namespace blender::bke::node_interface
684
685using namespace blender::bke::node_interface;
686
687blender::bke::bNodeSocketType *bNodeTreeInterfaceSocket::socket_typeinfo() const
688{
690}
691
692blender::ColorGeometry4f bNodeTreeInterfaceSocket::socket_color() const
693{
694 blender::bke::bNodeSocketType *typeinfo = this->socket_typeinfo();
695 if (typeinfo && typeinfo->draw_color_simple) {
696 float color[4];
697 typeinfo->draw_color_simple(typeinfo, color);
699 }
700 return blender::ColorGeometry4f(1.0f, 0.0f, 1.0f, 1.0f);
701}
702
703bool bNodeTreeInterfaceSocket::set_socket_type(const StringRef new_socket_type)
704{
705 const std::optional<StringRef> idname = socket_types::try_get_supported_socket_type(
706 new_socket_type);
707 if (!idname) {
708 return false;
709 }
710
711 if (this->socket_data != nullptr) {
714 }
716
717 this->socket_type = BLI_strdupn(new_socket_type.data(), new_socket_type.size());
718 this->socket_data = socket_types::make_socket_data(new_socket_type);
719
720 blender::bke::bNodeSocketType *stype = this->socket_typeinfo();
722 *stype, NodeDefaultInputType(this->default_input)))
723 {
725 }
726
727 return true;
728}
729
730void bNodeTreeInterfaceSocket::init_from_socket_instance(const bNodeSocket *socket)
731{
732 const std::optional<StringRef> idname = socket_types::try_get_supported_socket_type(
733 socket->idname);
734 BLI_assert(idname.has_value());
735
736 if (this->socket_data != nullptr) {
739 }
741 if (socket->flag & SOCK_HIDE_VALUE) {
743 }
744
745 this->socket_type = BLI_strdupn(idname->data(), idname->size());
748}
749
750blender::IndexRange bNodeTreeInterfacePanel::items_range() const
751{
752 return blender::IndexRange(items_num);
753}
754
755blender::Span<const bNodeTreeInterfaceItem *> bNodeTreeInterfacePanel::items() const
756{
757 return blender::Span(items_array, items_num);
758}
759
760blender::MutableSpan<bNodeTreeInterfaceItem *> bNodeTreeInterfacePanel::items()
761{
762 return blender::MutableSpan(items_array, items_num);
763}
764
765bool bNodeTreeInterfacePanel::contains(const bNodeTreeInterfaceItem &item) const
766{
767 return items().contains(&item);
768}
769
770bool bNodeTreeInterfacePanel::contains_recursive(const bNodeTreeInterfaceItem &item) const
771{
772 bool is_child = false;
773 /* Have to capture item address here instead of just a reference,
774 * otherwise pointer comparison will not work. */
775 this->foreach_item(
776 [&](const bNodeTreeInterfaceItem &titem) {
777 if (&titem == &item) {
778 is_child = true;
779 return false;
780 }
781 return true;
782 },
783 true);
784 return is_child;
785}
786
787int bNodeTreeInterfacePanel::item_position(const bNodeTreeInterfaceItem &item) const
788{
789 return items().first_index_try(&item);
790}
791
792int bNodeTreeInterfacePanel::item_index(const bNodeTreeInterfaceItem &item) const
793{
794 int index = 0;
795 bool found = false;
796 /* Have to capture item address here instead of just a reference,
797 * otherwise pointer comparison will not work. */
798 this->foreach_item([&](const bNodeTreeInterfaceItem &titem) {
799 if (&titem == &item) {
800 found = true;
801 return false;
802 }
803 ++index;
804 return true;
805 });
806 return found ? index : -1;
807}
808
809const bNodeTreeInterfaceItem *bNodeTreeInterfacePanel::item_at_index(int index) const
810{
811 int i = 0;
812 const bNodeTreeInterfaceItem *result = nullptr;
813 this->foreach_item([&](const bNodeTreeInterfaceItem &item) {
814 if (i == index) {
815 result = &item;
816 return false;
817 }
818 ++i;
819 return true;
820 });
821 return result;
822}
823
824bNodeTreeInterfacePanel *bNodeTreeInterfacePanel::find_parent_recursive(
825 const bNodeTreeInterfaceItem &item)
826{
827 std::queue<bNodeTreeInterfacePanel *> queue;
828
829 if (this->contains(item)) {
830 return this;
831 }
832 queue.push(this);
833
834 while (!queue.empty()) {
835 bNodeTreeInterfacePanel *parent = queue.front();
836 queue.pop();
837
838 for (bNodeTreeInterfaceItem *titem : parent->items()) {
839 if (titem->item_type != NODE_INTERFACE_PANEL) {
840 continue;
841 }
842
844 if (tpanel->contains(item)) {
845 return tpanel;
846 }
847 queue.push(tpanel);
848 }
849 }
850
851 return nullptr;
852}
853
854int bNodeTreeInterfacePanel::find_valid_insert_position_for_item(
855 const bNodeTreeInterfaceItem &item, const int initial_pos) const
856{
857 const bool sockets_above_panels = !(this->flag &
859 const blender::Span<const bNodeTreeInterfaceItem *> items = this->items();
860
861 /* True if item a should be above item b. */
862 auto must_be_before = [sockets_above_panels](const bNodeTreeInterfaceItem &a,
863 const bNodeTreeInterfaceItem &b) -> bool {
864 /* Keep sockets above panels. */
865 if (sockets_above_panels) {
866 if (a.item_type == NODE_INTERFACE_SOCKET && b.item_type == NODE_INTERFACE_PANEL) {
867 return true;
868 }
869 }
870 /* Keep outputs above inputs. */
871 if (a.item_type == NODE_INTERFACE_SOCKET && b.item_type == NODE_INTERFACE_SOCKET) {
872 const auto &sa = reinterpret_cast<const bNodeTreeInterfaceSocket &>(a);
873 const auto &sb = reinterpret_cast<const bNodeTreeInterfaceSocket &>(b);
874 const bool is_output_a = sa.flag & NODE_INTERFACE_SOCKET_OUTPUT;
875 const bool is_output_b = sb.flag & NODE_INTERFACE_SOCKET_OUTPUT;
876 if ((sa.flag & NODE_INTERFACE_SOCKET_PANEL_TOGGLE) ||
878 {
879 /* Panel toggle inputs are allowed to be above outputs. */
880 return false;
881 }
882 if (is_output_a && !is_output_b) {
883 return true;
884 }
885 }
886 return false;
887 };
888
889 int min_pos = 0;
890 for (const int i : items.index_range()) {
891 if (must_be_before(*items[i], item)) {
892 min_pos = i + 1;
893 }
894 }
895 int max_pos = items.size();
896 for (const int i : items.index_range()) {
897 if (must_be_before(item, *items[i])) {
898 max_pos = i;
899 break;
900 }
901 }
902 BLI_assert(min_pos <= max_pos);
903 return std::clamp(initial_pos, min_pos, max_pos);
904}
905
906void bNodeTreeInterfacePanel::add_item(bNodeTreeInterfaceItem &item)
907{
908 /* Same as inserting at the end. */
909 insert_item(item, this->items_num);
910}
911
912void bNodeTreeInterfacePanel::insert_item(bNodeTreeInterfaceItem &item, int position)
913{
914 /* Apply any constraints on the item positions. */
915 position = find_valid_insert_position_for_item(item, position);
916 position = std::min(std::max(position, 0), items_num);
917
918 blender::MutableSpan<bNodeTreeInterfaceItem *> old_items = this->items();
919 items_num++;
921 this->items().take_front(position).copy_from(old_items.take_front(position));
922 this->items().drop_front(position + 1).copy_from(old_items.drop_front(position));
923 this->items()[position] = &item;
924
925 if (old_items.data()) {
926 MEM_freeN(old_items.data());
927 }
928}
929
930bool bNodeTreeInterfacePanel::remove_item(bNodeTreeInterfaceItem &item, const bool free)
931{
932 const int position = this->item_position(item);
933 if (!this->items().index_range().contains(position)) {
934 return false;
935 }
936
937 blender::MutableSpan<bNodeTreeInterfaceItem *> old_items = this->items();
938 items_num--;
940 this->items().take_front(position).copy_from(old_items.take_front(position));
941 this->items().drop_front(position).copy_from(old_items.drop_front(position + 1));
942
943 /* Guaranteed not empty, contains at least the removed item */
944 MEM_freeN(old_items.data());
945
946 if (free) {
948 }
949
950 return true;
951}
952
953void bNodeTreeInterfacePanel::clear(bool do_id_user)
954{
955 for (bNodeTreeInterfaceItem *item : this->items()) {
956 item_types::item_free(*item, do_id_user);
957 }
959 items_array = nullptr;
960 items_num = 0;
961}
962
963bool bNodeTreeInterfacePanel::move_item(bNodeTreeInterfaceItem &item, int new_position)
964{
965 const int old_position = this->item_position(item);
966 if (!this->items().index_range().contains(old_position)) {
967 return false;
968 }
969 if (old_position == new_position) {
970 /* Nothing changes. */
971 return true;
972 }
973
974 new_position = find_valid_insert_position_for_item(item, new_position);
975 new_position = std::min(std::max(new_position, 0), items_num);
976
977 if (old_position < new_position) {
978 /* Actual target position and all existing items shifted by 1. */
979 const blender::Span<bNodeTreeInterfaceItem *> moved_items = this->items().slice(
980 old_position + 1, new_position - old_position - 1);
981 bNodeTreeInterfaceItem *tmp = this->items()[old_position];
982 std::copy(
983 moved_items.begin(), moved_items.end(), this->items().drop_front(old_position).data());
984 this->items()[new_position - 1] = tmp;
985 }
986 else /* old_position > new_position */ {
987 const blender::Span<bNodeTreeInterfaceItem *> moved_items = this->items().slice(
988 new_position, old_position - new_position);
989 bNodeTreeInterfaceItem *tmp = this->items()[old_position];
990 std::copy_backward(
991 moved_items.begin(), moved_items.end(), this->items().drop_front(old_position + 1).data());
992 this->items()[new_position] = tmp;
993 }
994
995 return true;
996}
997
998void bNodeTreeInterfacePanel::foreach_item(
999 blender::FunctionRef<bool(bNodeTreeInterfaceItem &item)> fn, bool include_self)
1000{
1001 using ItemSpan = blender::Span<bNodeTreeInterfaceItem *>;
1002 blender::Stack<ItemSpan> stack;
1003
1004 if (include_self && fn(this->item) == false) {
1005 return;
1006 }
1007 stack.push(this->items());
1008
1009 while (!stack.is_empty()) {
1010 const ItemSpan current_items = stack.pop();
1011
1012 for (const int index : current_items.index_range()) {
1013 bNodeTreeInterfaceItem *item = current_items[index];
1014 if (fn(*item) == false) {
1015 return;
1016 }
1017
1018 if (item->item_type == NODE_INTERFACE_PANEL) {
1019 bNodeTreeInterfacePanel *panel = reinterpret_cast<bNodeTreeInterfacePanel *>(item);
1020 /* Reinsert remaining items. */
1021 if (index < current_items.size() - 1) {
1022 const ItemSpan remaining_items = current_items.drop_front(index + 1);
1023 stack.push(remaining_items);
1024 }
1025 /* Handle child items first before continuing with current span. */
1026 stack.push(panel->items());
1027 break;
1028 }
1029 }
1030 }
1031}
1032
1033void bNodeTreeInterfacePanel::foreach_item(
1034 blender::FunctionRef<bool(const bNodeTreeInterfaceItem &item)> fn, bool include_self) const
1035{
1036 using ItemSpan = blender::Span<const bNodeTreeInterfaceItem *>;
1037 blender::Stack<ItemSpan> stack;
1038
1039 if (include_self && fn(this->item) == false) {
1040 return;
1041 }
1042 stack.push(this->items());
1043
1044 while (!stack.is_empty()) {
1045 const ItemSpan current_items = stack.pop();
1046
1047 for (const int index : current_items.index_range()) {
1048 const bNodeTreeInterfaceItem *item = current_items[index];
1049 if (fn(*item) == false) {
1050 return;
1051 }
1052
1053 if (item->item_type == NODE_INTERFACE_PANEL) {
1054 const bNodeTreeInterfacePanel *panel = reinterpret_cast<const bNodeTreeInterfacePanel *>(
1055 item);
1056 /* Reinsert remaining items. */
1057 if (index < current_items.size() - 1) {
1058 const ItemSpan remaining_items = current_items.drop_front(index + 1);
1059 stack.push(remaining_items);
1060 }
1061 /* Handle child items first before continuing with current span. */
1062 stack.push(panel->items());
1063 break;
1064 }
1065 }
1066 }
1067}
1068
1069const bNodeTreeInterfaceSocket *bNodeTreeInterfacePanel::header_toggle_socket() const
1070{
1071 if (this->items().is_empty()) {
1072 return nullptr;
1073 }
1074 const bNodeTreeInterfaceItem *first_item = this->items().first();
1075 if (first_item->item_type != NODE_INTERFACE_SOCKET) {
1076 return nullptr;
1077 }
1078 const auto &socket = *reinterpret_cast<const bNodeTreeInterfaceSocket *>(first_item);
1079 if (!(socket.flag & NODE_INTERFACE_SOCKET_INPUT) ||
1081 {
1082 return nullptr;
1083 }
1084 const blender::bke::bNodeSocketType *typeinfo = socket.socket_typeinfo();
1085 if (!typeinfo || typeinfo->type != SOCK_BOOLEAN) {
1086 return nullptr;
1087 }
1088 return &socket;
1089}
1090bNodeTreeInterfaceSocket *bNodeTreeInterfacePanel::header_toggle_socket()
1091{
1092 return const_cast<bNodeTreeInterfaceSocket *>(
1093 const_cast<const bNodeTreeInterfacePanel *>(this)->header_toggle_socket());
1094}
1095
1097
1099 const StringRef name,
1100 const StringRef description,
1101 const StringRef socket_type,
1103{
1104 BLI_assert(!socket_type.is_empty());
1105
1106 const std::optional<StringRef> idname = socket_types::try_get_supported_socket_type(socket_type);
1107 if (!idname) {
1108 return nullptr;
1109 }
1110
1112 BLI_assert(new_socket);
1113
1114 /* Init common socket properties. */
1115 new_socket->identifier = BLI_sprintfN("Socket_%d", uid);
1116 new_socket->item.item_type = NODE_INTERFACE_SOCKET;
1117 new_socket->name = BLI_strdupn(name.data(), name.size());
1118 new_socket->description = description.is_empty() ?
1119 nullptr :
1120 BLI_strdupn(description.data(), description.size());
1121 new_socket->socket_type = BLI_strdupn(socket_type.data(), socket_type.size());
1122 new_socket->flag = flag;
1123
1124 new_socket->socket_data = socket_types::make_socket_data(socket_type);
1125
1126 return new_socket;
1127}
1128
1130 const bNode &from_node,
1131 const bNodeSocket &from_sock,
1132 const StringRef socket_type,
1133 const StringRef name)
1134{
1135 ntree.ensure_topology_cache();
1136 bNodeTreeInterfaceSocket *iosock = nullptr;
1137 if (from_node.is_group()) {
1138 if (const bNodeTree *group = reinterpret_cast<const bNodeTree *>(from_node.id)) {
1139 /* Copy interface socket directly from source group to avoid loosing data in the process. */
1140 group->ensure_interface_cache();
1141 const bNodeTreeInterfaceSocket &src_io_socket =
1142 from_sock.is_input() ? *group->interface_inputs()[from_sock.index()] :
1143 *group->interface_outputs()[from_sock.index()];
1144 iosock = reinterpret_cast<bNodeTreeInterfaceSocket *>(
1145 ntree.tree_interface.add_item_copy(src_io_socket.item, nullptr));
1146 }
1147 }
1148 if (!iosock) {
1152
1153 const nodes::SocketDeclaration *decl = from_sock.runtime->declaration;
1154 StringRef description = from_sock.description;
1155 if (decl) {
1156 if (!decl->description.empty()) {
1157 description = decl->description;
1158 }
1159 }
1160
1161 iosock = ntree.tree_interface.add_socket(name, description, socket_type, flag, nullptr);
1162
1163 if (iosock) {
1164 if (decl) {
1165 iosock->default_input = decl->default_input_type;
1166 }
1167 }
1168 }
1169 if (iosock == nullptr) {
1170 return nullptr;
1171 }
1172 const blender::bke::bNodeSocketType *typeinfo = iosock->socket_typeinfo();
1173 if (typeinfo->interface_from_socket) {
1174 typeinfo->interface_from_socket(&ntree.id, iosock, &from_node, &from_sock);
1175 }
1176 return iosock;
1177}
1178
1180 const blender::StringRef name,
1181 const blender::StringRef description,
1183{
1184 BLI_assert(!name.is_empty());
1185
1187 new_panel->item.item_type = NODE_INTERFACE_PANEL;
1188 new_panel->name = BLI_strdupn(name.data(), name.size());
1189 new_panel->description = description.is_empty() ?
1190 nullptr :
1191 BLI_strdupn(description.data(), description.size());
1192 new_panel->identifier = uid;
1193 new_panel->flag = flag;
1194 return new_panel;
1195}
1196
1197} // namespace blender::bke::node_interface
1198
1199void bNodeTreeInterface::init_data()
1200{
1201 this->runtime = MEM_new<blender::bke::bNodeTreeInterfaceRuntime>(__func__);
1202 this->tag_missing_runtime_data();
1203}
1204
1205void bNodeTreeInterface::copy_data(const bNodeTreeInterface &src, int flag)
1206{
1207 item_types::panel_init(this->root_panel, src.root_panel.items(), flag, nullptr);
1208 this->active_index = src.active_index;
1209
1210 this->runtime = MEM_new<blender::bke::bNodeTreeInterfaceRuntime>(__func__);
1211 this->tag_missing_runtime_data();
1212}
1213
1214void bNodeTreeInterface::free_data()
1215{
1216 MEM_delete(this->runtime);
1217
1218 /* Called when freeing the main database, don't do user refcount here. */
1219 this->root_panel.clear(false);
1220}
1221
1222void bNodeTreeInterface::write(BlendWriter *writer)
1223{
1224 /* Don't write the root panel struct itself, it's nested in the interface struct. */
1225 item_types::item_write_data(writer, this->root_panel.item);
1226}
1227
1228void bNodeTreeInterface::read_data(BlendDataReader *reader)
1229{
1230 item_types::item_read_data(reader, this->root_panel.item);
1231
1232 this->runtime = MEM_new<blender::bke::bNodeTreeInterfaceRuntime>(__func__);
1233 this->tag_missing_runtime_data();
1234}
1235
1236bNodeTreeInterfaceItem *bNodeTreeInterface::active_item()
1237{
1238 bNodeTreeInterfaceItem *active = nullptr;
1239 int count = this->active_index;
1240 this->foreach_item([&](bNodeTreeInterfaceItem &item) {
1241 if (count == 0) {
1242 active = &item;
1243 return false;
1244 }
1245 --count;
1246 return true;
1247 });
1248 return active;
1249}
1250
1251const bNodeTreeInterfaceItem *bNodeTreeInterface::active_item() const
1252{
1253 const bNodeTreeInterfaceItem *active = nullptr;
1254 int count = this->active_index;
1255 this->foreach_item([&](const bNodeTreeInterfaceItem &item) {
1256 if (count == 0) {
1257 active = &item;
1258 return false;
1259 }
1260 --count;
1261 return true;
1262 });
1263 return active;
1264}
1265
1266void bNodeTreeInterface::active_item_set(bNodeTreeInterfaceItem *item)
1267{
1268 this->active_index = 0;
1269 int count = 0;
1270 this->foreach_item([&](bNodeTreeInterfaceItem &titem) {
1271 if (&titem == item) {
1272 this->active_index = count;
1273 return false;
1274 }
1275 ++count;
1276 return true;
1277 });
1278}
1279
1280bNodeTreeInterfaceSocket *bNodeTreeInterface::add_socket(const blender::StringRef name,
1281 const blender::StringRef description,
1282 const blender::StringRef socket_type,
1285{
1286 /* Check that each interface socket is either an input or an output. Technically, it can be both
1287 * at the same time, but we don't want that for the time being. */
1290 if (parent == nullptr) {
1291 parent = &root_panel;
1292 }
1293 BLI_assert(this->find_item(parent->item));
1294
1296 this->next_uid++, name, description, socket_type, flag);
1297 if (new_socket) {
1298 parent->add_item(new_socket->item);
1299 }
1300
1301 this->tag_items_changed();
1302 return new_socket;
1303}
1304
1305bNodeTreeInterfaceSocket *bNodeTreeInterface::insert_socket(const blender::StringRef name,
1306 const blender::StringRef description,
1307 const blender::StringRef socket_type,
1310 const int position)
1311{
1312 if (parent == nullptr) {
1313 parent = &root_panel;
1314 }
1315 BLI_assert(this->find_item(parent->item));
1316
1318 this->next_uid++, name, description, socket_type, flag);
1319 if (new_socket) {
1320 parent->insert_item(new_socket->item, position);
1321 }
1322
1323 this->tag_items_changed();
1324 return new_socket;
1325}
1326
1327bNodeTreeInterfacePanel *bNodeTreeInterface::add_panel(const blender::StringRef name,
1328 const blender::StringRef description,
1331{
1332 if (parent == nullptr) {
1333 parent = &root_panel;
1334 }
1335 BLI_assert(this->find_item(parent->item));
1336
1337 bNodeTreeInterfacePanel *new_panel = make_panel(this->next_uid++, name, description, flag);
1338 if (new_panel) {
1339 parent->add_item(new_panel->item);
1340 }
1341
1342 this->tag_items_changed();
1343 return new_panel;
1344}
1345
1346bNodeTreeInterfacePanel *bNodeTreeInterface::insert_panel(const blender::StringRef name,
1347 const blender::StringRef description,
1350 const int position)
1351{
1352 if (parent == nullptr) {
1353 parent = &root_panel;
1354 }
1355 BLI_assert(this->find_item(parent->item));
1356
1357 bNodeTreeInterfacePanel *new_panel = make_panel(this->next_uid++, name, description, flag);
1358 if (new_panel) {
1359 parent->insert_item(new_panel->item, position);
1360 }
1361
1362 this->tag_items_changed();
1363 return new_panel;
1364}
1365
1366bNodeTreeInterfaceItem *bNodeTreeInterface::add_item_copy(const bNodeTreeInterfaceItem &item,
1368{
1369 if (parent == nullptr) {
1370 parent = &root_panel;
1371 }
1372 BLI_assert(this->find_item(parent->item));
1373
1374 bNodeTreeInterfaceItem *citem = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(&item));
1375 item_types::item_copy(*citem, item, 0, [&]() { return this->next_uid++; });
1376 parent->add_item(*citem);
1377
1378 this->tag_items_changed();
1379 return citem;
1380}
1381
1382bNodeTreeInterfaceItem *bNodeTreeInterface::insert_item_copy(const bNodeTreeInterfaceItem &item,
1384 int position)
1385{
1386 if (parent == nullptr) {
1387 parent = &root_panel;
1388 }
1389 BLI_assert(this->find_item(item));
1390 BLI_assert(this->find_item(parent->item));
1391
1392 bNodeTreeInterfaceItem *citem = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(&item));
1393 item_types::item_copy(*citem, item, 0, [&]() { return this->next_uid++; });
1394 parent->insert_item(*citem, position);
1395
1396 this->tag_items_changed();
1397 return citem;
1398}
1399
1400bool bNodeTreeInterface::remove_item(bNodeTreeInterfaceItem &item, bool move_content_to_parent)
1401{
1402 bNodeTreeInterfacePanel *parent = this->find_item_parent(item, true);
1403 if (parent == nullptr) {
1404 return false;
1405 }
1406 if (move_content_to_parent) {
1407 int position = parent->item_position(item);
1408 /* Cache children to avoid invalidating the iterator. */
1409 blender::Array<bNodeTreeInterfaceItem *> children(item_types::item_children(item));
1410 for (bNodeTreeInterfaceItem *child : children) {
1411 this->move_item_to_parent(*child, parent, position++);
1412 }
1413 }
1414 if (parent->remove_item(item, true)) {
1415 this->tag_items_changed();
1416 return true;
1417 }
1418
1419 return false;
1420}
1421
1422void bNodeTreeInterface::clear_items()
1423{
1424 root_panel.clear(true);
1425 this->tag_items_changed();
1426}
1427
1428bool bNodeTreeInterface::move_item(bNodeTreeInterfaceItem &item, const int new_position)
1429{
1430 bNodeTreeInterfacePanel *parent = this->find_item_parent(item, true);
1431 if (parent == nullptr) {
1432 return false;
1433 }
1434
1435 if (parent->move_item(item, new_position)) {
1436 this->tag_items_changed();
1437 return true;
1438 }
1439 return false;
1440}
1441
1442bool bNodeTreeInterface::move_item_to_parent(bNodeTreeInterfaceItem &item,
1443 bNodeTreeInterfacePanel *new_parent,
1444 int new_position)
1445{
1446 if (new_parent == nullptr) {
1447 new_parent = &this->root_panel;
1448 }
1449
1450 if (item.item_type == NODE_INTERFACE_PANEL) {
1451 bNodeTreeInterfacePanel &src_item = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
1452 if (src_item.contains_recursive(new_parent->item)) {
1453 return false;
1454 }
1455 }
1456
1457 bNodeTreeInterfacePanel *parent = this->find_item_parent(item, true);
1458 if (parent == nullptr) {
1459 return false;
1460 }
1461
1462 if (parent == new_parent) {
1463 if (parent->move_item(item, new_position)) {
1464 this->tag_items_changed();
1465 return true;
1466 }
1467 }
1468 else {
1469 /* NOTE: only remove and reinsert when parents different, otherwise removing the item can
1470 * change the desired target position! */
1471 if (parent->remove_item(item, false)) {
1472 new_parent->insert_item(item, new_position);
1473 this->tag_items_changed();
1474 return true;
1475 }
1476 }
1477 return false;
1478}
1479
1480void bNodeTreeInterface::foreach_id(LibraryForeachIDData *cb)
1481{
1483}
1484
1485bool bNodeTreeInterface::items_cache_is_available() const
1486{
1487 return !this->runtime->items_cache_mutex_.is_dirty();
1488}
1489
1490void bNodeTreeInterface::ensure_items_cache() const
1491{
1492 blender::bke::bNodeTreeInterfaceRuntime &runtime = *this->runtime;
1493
1494 runtime.items_cache_mutex_.ensure([&]() {
1495 /* Rebuild draw-order list of interface items for linear access. */
1496 runtime.items_.clear();
1497 runtime.inputs_.clear();
1498 runtime.outputs_.clear();
1499
1500 /* Items in the cache are mutable pointers, but node tree update considers ID data to be
1501 * immutable when caching. DNA ListBase pointers can be mutable even if their container is
1502 * const, but the items returned by #foreach_item inherit qualifiers from the container. */
1503 bNodeTreeInterface &mutable_self = const_cast<bNodeTreeInterface &>(*this);
1504
1505 mutable_self.foreach_item([&](bNodeTreeInterfaceItem &item) {
1506 runtime.items_.add_new(&item);
1508 if (socket->flag & NODE_INTERFACE_SOCKET_INPUT) {
1509 runtime.inputs_.add_new(socket);
1510 }
1511 if (socket->flag & NODE_INTERFACE_SOCKET_OUTPUT) {
1512 runtime.outputs_.add_new(socket);
1513 }
1514 }
1515 return true;
1516 });
1517 });
1518}
1519
1520void bNodeTreeInterface::tag_interface_changed()
1521{
1522 this->runtime->interface_changed_.store(true);
1523}
1524
1525bool bNodeTreeInterface::requires_dependent_tree_updates() const
1526{
1527 return this->runtime->interface_changed_.load(std::memory_order_relaxed);
1528}
1529
1530void bNodeTreeInterface::tag_items_changed()
1531{
1532 this->tag_interface_changed();
1533 this->runtime->items_cache_mutex_.tag_dirty();
1534}
1535
1536void bNodeTreeInterface::tag_items_changed_generic()
1537{
1538 /* Perform a full update since we don't know what changed exactly. */
1539 this->tag_items_changed();
1540}
1541
1542void bNodeTreeInterface::tag_item_property_changed()
1543{
1544 this->tag_interface_changed();
1545}
1546
1547void bNodeTreeInterface::tag_missing_runtime_data()
1548{
1549 this->tag_items_changed();
1550}
1551
1552void bNodeTreeInterface::reset_interface_changed()
1553{
1554 this->runtime->interface_changed_.store(false);
1555}
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:1205
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:855
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1453
void id_us_plus(ID *id)
Definition lib_id.cc:353
@ LIB_ID_CREATE_NO_USER_REFCOUNT
void id_us_min(ID *id)
Definition lib_id.cc:361
#define BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data_, func_call_)
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_USER
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_kdtree_nd_ free(KDTree *tree)
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.cc:41
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:30
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.cc:46
#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:5351
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_write_pointer_array(BlendWriter *writer, int64_t num, const void *data_ptr)
void BLO_read_pointer_array(BlendDataReader *reader, int64_t array_size, void **ptr_p)
Definition readfile.cc:5402
@ IDP_TYPE_FILTER_ID
Object groups, one object can be in many groups at once.
@ NODE_INTERFACE_PANEL_ALLOW_SOCKETS_AFTER_PANELS
@ NODE_INTERFACE_SOCKET_SINGLE_VALUE_ONLY_LEGACY
@ NODE_INTERFACE_SOCKET_PANEL_TOGGLE
@ NODE_INTERFACE_SOCKET_HIDE_VALUE
struct bNodeTreeInterface bNodeTreeInterface
struct bNodeTreeInterfaceSocket bNodeTreeInterfaceSocket
struct bNodeTreeInterfacePanel bNodeTreeInterfacePanel
@ NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_SINGLE
struct bNodeTreeInterfaceItem bNodeTreeInterfaceItem
@ SOCK_OUT
@ SOCK_IN
@ SOCK_HIDE_VALUE
@ SOCK_BOOLEAN
@ PROP_NONE
Definition RNA_types.hh:221
BMesh const char void * data
constexpr T * data() const
Definition BLI_span.hh:539
constexpr MutableSpan drop_front(const int64_t n) const
Definition BLI_span.hh:607
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:629
constexpr Span drop_front(int64_t n) const
Definition BLI_span.hh:171
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr const T & first() const
Definition BLI_span.hh:315
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr const T * end() const
Definition BLI_span.hh:224
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr const T * begin() const
Definition BLI_span.hh:220
constexpr Span take_front(int64_t n) const
Definition BLI_span.hh:193
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
#define active
#define this
#define MEM_SAFE_FREE(v)
int count
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
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 std::optional< StringRef > try_get_supported_socket_type(const StringRef socket_type)
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 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)
bNodeTreeInterfaceSocket * add_interface_socket_from_node(bNodeTree &ntree, const bNode &from_node, const bNodeSocket &from_sock, StringRef socket_type, StringRef name)
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)
bNodeSocketType * node_socket_type_find(StringRef idname)
Definition node.cc:2794
std::optional< StringRefNull > node_static_socket_type(int type, int subtype, std::optional< int > dimensions=std::nullopt)
Definition node.cc:3167
bool node_is_static_socket_type(const bNodeSocketType &stype)
Definition node.cc:3158
bool socket_type_supports_default_input_type(const bke::bNodeSocketType &socket_type, const NodeDefaultInputType input_type)
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
static bool is_child(const Object *ob, const Object *parent)
#define FLT_MAX
Definition stdcycles.h:14
Definition DNA_ID.h:404
const RuntimeNodeEnumItemsHandle * enum_items
bNodeSocketRuntimeHandle * runtime
char description[64]
void * default_value
char idname[64]
bNodeTreeInterfaceItem ** items_array
bNodeTreeInterfacePanel root_panel
bNodeTreeInterfaceRuntimeHandle * runtime
bNodeTreeInterface tree_interface
struct ID * id
Defines a socket type.
Definition BKE_node.hh:152
void(* draw_color_simple)(const bNodeSocketType *socket_type, float *r_color)
Definition BKE_node.hh:166
eNodeSocketDatatype type
Definition BKE_node.hh:187
void(* interface_from_socket)(ID *id, bNodeTreeInterfaceSocket *interface_socket, const bNode *node, const bNodeSocket *socket)
Definition BKE_node.hh:177
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:139