64 if (socket->identifier == identifier) {
137 const char **r_disabled_hint)
139 if (!
node->typeinfo->poll(
node->typeinfo, nodetree, r_disabled_hint)) {
168 const char **r_disabled_hint)
173 if (grouptree ==
nullptr) {
177 if (nodetree == grouptree) {
178 if (r_disabled_hint) {
179 *r_disabled_hint =
RPT_(
"Nesting a node group inside of itself is not allowed");
183 if (nodetree->
type != grouptree->
type) {
184 if (r_disabled_hint) {
185 *r_disabled_hint =
RPT_(
"Node group has different type");
190 for (
const bNode *
node : grouptree->all_nodes()) {
191 if (
node->typeinfo->poll_instance &&
192 !
node->typeinfo->poll_instance(
node, nodetree, r_disabled_hint))
205 const int item_index = tree_interface.find_item_index(io_socket.
item);
210 if (
node.id ==
nullptr) {
230 const int item_index =
interface.find_item_index(io_socket.
item);
235 if (
node.id ==
nullptr) {
258 const std::optional<StructureType> structure_type,
271 datatype = base_typeinfo->
type;
277 .default_value(
value.value)
287 .dimensions(
value.dimensions)
321 .default_value(
value.value)
330 .default_value(
value.value);
336 .default_value(
value.value)
394 if (structure_type) {
411 bool layout_added =
false;
412 auto add_layout_if_needed = [&]() {
414 if (
node.typeinfo->draw_buttons) {
415 if (is_root && !layout_added) {
416 b.add_default_layout();
429 add_layout_if_needed();
432 group, io_socket, structure_type_by_socket.
lookup_try(&io_socket), in_out,
b);
436 add_layout_if_needed();
438 auto &panel_b =
b.add_panel(
StringRef(io_panel.name), io_panel.identifier)
439 .description(
StringRef(io_panel.description))
442 panel_b,
node, group, structure_type_by_socket, io_panel,
false);
448 add_layout_if_needed();
454 if (
node ==
nullptr) {
471 group->ensure_interface_cache();
475 structure_type_by_socket.
reserve(group->interface_items().size());
479 group->
runtime->structure_type_interface->inputs;
480 for (
const int i :
inputs.index_range()) {
481 structure_type_by_socket.
add(
inputs[i], input_structure_types[i]);
486 group->
runtime->structure_type_interface->outputs;
487 for (
const int i :
outputs.index_range()) {
488 structure_type_by_socket.
add(
outputs[i], output_structure_types[i].type);
496 group->ensure_interface_cache();
499 *group->
runtime->field_inferencing_interface;
500 for (
const int i :
inputs.index_range()) {
505 for (
const int i : r_declaration.
outputs.index_range()) {
506 r_declaration.
outputs[i]->output_field_dependency = field_interface.
outputs[i];
526 data->label_size = 20;
538 "Collect related nodes together in a common area. Useful for organization when the "
539 "re-usability of a node group is not required";
560 if (
node ==
nullptr) {
567 .idname(socket_idname.
c_str())
568 .structure_type(blender::nodes::StructureType::Dynamic);
570 .idname(socket_idname.
c_str())
571 .structure_type(blender::nodes::StructureType::Dynamic);
590 "A single-socket organization tool that supports one input and multiple outputs";
601 int node_i = std::numeric_limits<int>::max();
612 if (this->node_i == other.
node_i) {
615 return this->node_i < other.
node_i;
622 ntree->ensure_topology_cache();
624 const Span<bNode *> all_reroute_nodes = ntree->nodes_by_type(
"NodeReroute");
627 for (
const bNode *reroute : all_reroute_nodes) {
628 reroute_nodes.
add(reroute->index());
638 for (
const bNode *src_reroute : all_reroute_nodes) {
639 const int src_reroute_i = reroute_nodes.
index_of(src_reroute->index());
641 src_reroute->output_sockets().first()->directly_linked_sockets())
643 const bNode &dst_node = dst_socket->owner_node();
644 if (!dst_node.is_reroute()) {
647 const int dst_reroute_i = reroute_nodes.
index_of(dst_node.index());
648 reroutes_groups.
join(src_reroute_i, dst_reroute_i);
653 for (
const int reroute_i : reroute_nodes.
index_range()) {
654 const int root_reroute_i = reroutes_groups.find_root(reroute_i);
655 reroute_groups.
add(root_reroute_i);
668 for (
const bNodeLink *link : ntree->all_links()) {
669 const bNode *src_node = link->fromnode;
670 const bNode *dst_node = link->tonode;
672 if (src_node->is_reroute() == dst_node->is_reroute()) {
676 if (!dst_node->is_reroute()) {
677 const int src_reroute_i = reroute_nodes.
index_of(src_node->index());
678 const int src_reroute_root_i = reroutes_groups.find_root(src_reroute_i);
679 const int src_reroute_group_i = reroute_groups.
index_of(src_reroute_root_i);
682 if (reroute_group_dst_type_priority[src_reroute_group_i] > type_priority) {
686 reroute_group_dst_type_priority[src_reroute_group_i] = type_priority;
691 dst_type_by_reroute_group[src_reroute_group_i] = dst_socket->
typeinfo;
696 const int dst_reroute_i = reroute_nodes.
index_of(dst_node->index());
697 const int dst_reroute_root_i = reroutes_groups.find_root(dst_reroute_i);
698 const int dst_reroute_group_i = reroute_groups.
index_of(dst_reroute_root_i);
703 src_type_by_reroute_group[dst_reroute_group_i] = src_socket->
typeinfo;
707 for (
const int reroute_i : reroute_nodes.
index_range()) {
708 const int reroute_root_i = reroutes_groups.find_root(reroute_i);
709 const int reroute_group_i = reroute_groups.
index_of(reroute_root_i);
712 if (dst_type_by_reroute_group[reroute_group_i] !=
nullptr) {
713 reroute_type = dst_type_by_reroute_group[reroute_group_i];
715 if (src_type_by_reroute_group[reroute_group_i] !=
nullptr) {
716 reroute_type = src_type_by_reroute_group[reroute_group_i];
719 if (reroute_type ==
nullptr) {
723 const int reroute_index = reroute_nodes[reroute_i];
724 bNode &reroute_node = *all_nodes[reroute_index];
727 nodes::update_node_declaration_and_sockets(*ntree, reroute_node);
733 ntree.ensure_topology_cache();
736 for (
const bNodeLink *link : socket->directly_linked_links()) {
737 nodes_to_check.
push(link->tonode);
740 while (!nodes_to_check.
is_empty()) {
741 const bNode *next_node = nodes_to_check.
pop();
742 for (
const bNodeSocket *socket : next_node->output_sockets()) {
743 for (
const bNodeLink *link : socket->directly_linked_links()) {
749 nodes_to_check.
push(link->tonode);
766 if (sock->identifier == identifier) {
777 const bNodeTree *node_tree =
b.tree_or_null();
778 if (node_tree ==
nullptr) {
783 case NODE_INTERFACE_SOCKET: {
784 const bNodeTreeInterfaceSocket &socket =
785 node_interface::get_item_as<bNodeTreeInterfaceSocket>(item);
786 if (socket.flag & NODE_INTERFACE_SOCKET_INPUT) {
792 build_interface_socket_declaration(*node_tree, socket, std::nullopt, SOCK_OUT, b);
802 b.add_output<decl::Extend>(
"",
"__extend__");
807 const bNodeTree *node_tree =
b.tree_or_null();
808 if (node_tree ==
nullptr) {
813 case NODE_INTERFACE_SOCKET: {
814 const bNodeTreeInterfaceSocket &socket =
815 node_interface::get_item_as<bNodeTreeInterfaceSocket>(item);
816 if (socket.flag & NODE_INTERFACE_SOCKET_OUTPUT) {
817 build_interface_socket_declaration(*node_tree, socket, std::nullopt, SOCK_IN, b);
827 b.add_input<decl::Extend>(
"",
"__extend__");
881 ntype->
ui_name =
"Group Input";
883 "Expose connected data from inside a node group as inputs to its interface";
897 if (sock->identifier == identifier) {
908 if (group_output_nodes.
size() <= 1) {
916 row.
icon = ICON_ERROR;
917 row.
tooltip =
TIP_(
"There are multiple group output nodes and this one is not active");
918 params.rows.append(std::move(row));
928 ntype->
ui_name =
"Group Output";
929 ntype->
ui_description =
"Output data from inside of a node group";
#define NODE_CLASS_OUTPUT
#define NODE_CLASS_INTERFACE
#define NODE_CLASS_CONVERTER
#define NODE_CLASS_PATTERN
#define NODE_CLASS_GEOMETRY
#define NODE_GROUP_OUTPUT
#define NODE_CLASS_DISTORT
#define NODE_CLASS_OP_VECTOR
#define NODE_CLASS_LAYOUT
#define NODE_CLASS_OP_COLOR
#define NODE_CLASS_OP_FILTER
#define NODE_CLASS_ATTRIBUTE
#define NODE_CLASS_TEXTURE
#define NODE_CLASS_SHADER
#define NODE_CLASS_SCRIPT
#define LISTBASE_FOREACH(type, var, list)
char * STRNCPY(char(&dst)[N], const char *src)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define ID_IS_LINKED(_id)
NodeTreeInterfaceItemType
@ NODE_INTERFACE_PANEL_DEFAULT_CLOSED
@ NODE_INTERFACE_SOCKET_PANEL_TOGGLE
@ NODE_INTERFACE_SOCKET_INPUT
@ NODE_INTERFACE_SOCKET_MENU_EXPANDED
@ NODE_INTERFACE_SOCKET_COMPACT
@ NODE_INTERFACE_SOCKET_HIDE_VALUE
@ NODE_DEFAULT_INPUT_VALUE
Read Guarded memory(de)allocation.
void join(const size_t x, const size_t y)
std::optional< Value > lookup_try(const Key &key) const
bool add(const Key &key, const Value &value)
constexpr int64_t size() const
void push(const T &value)
constexpr bool startswith(StringRef prefix) const
void copy_utf8_truncated(char *dst, int64_t dst_size) const
constexpr const char * c_str() const
int64_t index_of(const Key &key) const
IndexRange index_range() const
BaseSocketDeclarationBuilder & compact(bool value=true)
BaseSocketDeclarationBuilder & structure_type(StructureType structure_type)
BaseSocketDeclarationBuilder & description(std::string value="")
BaseSocketDeclarationBuilder & panel_toggle(bool value=true)
BaseSocketDeclarationBuilder & hide_value(bool value=true)
BaseSocketDeclarationBuilder & default_input_type(NodeDefaultInputType value)
bool skip_updating_sockets
Vector< SocketDeclaration * > inputs
Vector< SocketDeclaration * > outputs
bool use_custom_socket_order
InputSocketFieldType input_field_type
std::function< void(bNode &node, bNodeSocket &socket, const char *data_path)> init_socket_fn
void * MEM_callocN(size_t len, const char *str)
T & get_item_as(bNodeTreeInterfaceItem &item)
bNodeTreeInterfaceSocket * add_interface_socket_from_node(bNodeTree &ntree, const bNode &from_node, const bNodeSocket &from_sock, StringRef socket_type, StringRef name)
T & get_socket_data_as(bNodeTreeInterfaceSocket &item)
bool node_is_connected_to_output(const bNodeTree &ntree, const bNode &node)
bool node_group_poll(const bNodeTree *nodetree, const bNodeTree *grouptree, const char **r_disabled_hint)
void node_type_size(bNodeType &ntype, int width, int minwidth, int maxwidth)
void node_register_type(bNodeType &ntype)
void node_type_base(bNodeType &ntype, std::string idname, std::optional< int16_t > legacy_type=std::nullopt)
bNodeSocketType * node_socket_type_find(StringRef idname)
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
static void group_input_declare(NodeDeclarationBuilder &b)
static std::function< ID *(const bNode &node)> get_default_id_getter(const bNodeTreeInterface &tree_interface, const bNodeTreeInterfaceSocket &io_socket)
static bool group_input_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
static std::function< void(bNode &node, bNodeSocket &socket, const char *data_path)> get_init_socket_fn(const bNodeTreeInterface &interface, const bNodeTreeInterfaceSocket &io_socket)
void node_group_declare(NodeDeclarationBuilder &b)
static void group_output_declare(NodeDeclarationBuilder &b)
compositor::NodeOperation * get_group_input_compositor_operation(compositor::Context &context, DNode node)
static bool group_output_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static BaseSocketDeclarationBuilder & build_interface_socket_declaration(const bNodeTree &tree, const bNodeTreeInterfaceSocket &io_socket, const std::optional< StructureType > structure_type, const eNodeSocketInOut in_out, DeclarationListBuilder &b)
static void node_group_declare_panel_recursive(DeclarationListBuilder &b, const bNode &node, const bNodeTree &group, const Map< const bNodeTreeInterfaceSocket *, StructureType > &structure_type_by_socket, const bNodeTreeInterfacePanel &io_parent_panel, const bool is_root)
VecBase< float, 4 > float4
VecBase< float, 3 > float3
static void node_group_output_extra_info(blender::nodes::NodeExtraInfoParams ¶ms)
static bNodeSocket * find_matching_socket(ListBase &sockets, StringRef identifier)
int node_group_ui_class(const bNode *node)
bNodeSocket * node_group_output_find_socket(bNode *node, const StringRef identifier)
bNodeSocket * node_group_input_find_socket(bNode *node, const StringRef identifier)
void register_node_type_group_output()
void node_group_label(const bNodeTree *, const bNode *node, char *label, int label_maxncpy)
void register_node_type_group_input()
bNodeSocket * node_group_find_input_socket(bNode *groupnode, const blender::StringRef identifier)
void ntree_update_reroute_nodes(bNodeTree *ntree)
static void node_frame_init(bNodeTree *, bNode *node)
bool node_group_poll_instance(const bNode *node, const bNodeTree *nodetree, const char **r_disabled_hint)
static void node_reroute_init(bNodeTree *, bNode *node)
void register_node_type_frame()
bNodeSocket * node_group_find_output_socket(bNode *groupnode, const blender::StringRef identifier)
static void node_reroute_declare(blender::nodes::NodeDeclarationBuilder &b)
std::string node_group_ui_description(const bNode &node)
void register_node_type_reroute()
static blender::bke::bNodeSocketTemplate outputs[]
static blender::bke::bNodeSocketTemplate inputs[]
void node_free_standard_storage(bNode *node)
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
struct AssetMetaData * asset_data
RerouteTargetPriority()=default
RerouteTargetPriority(const bNodeSocket &socket)
bool operator>(const RerouteTargetPriority other)
bNodeSocketTypeHandle * typeinfo
bNodeTreeInterfaceItem item
bNodeTreeInterfacePanel root_panel
bNodeTreeRuntimeHandle * runtime
bNodeTreeInterface tree_interface
void(* interface_init_socket)(ID *id, const bNodeTreeInterfaceSocket *interface_socket, bNode *node, bNodeSocket *socket, StringRefNull data_path)
std::string ui_description
NodeGetCompositorOperationFunction get_compositor_operation
void(* initfunc)(bNodeTree *ntree, bNode *node)
NodeExtraInfoFunction get_extra_info
const char * enum_name_legacy
bool(* insert_link)(bNodeTree *ntree, bNode *node, bNodeLink *link)
NodeDeclareFunction declare
void(* free_self)(bNodeType *ntype)
Array< InputSocketFieldType > inputs
Array< OutputFieldDependency > outputs