Blender V5.0
node_geo_separate_bundle.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "ED_screen.hh"
8
9#include "NOD_geo_bundle.hh"
15#include "NOD_sync_sockets.hh"
16
17#include "BKE_idprop.hh"
18
19#include "BLO_read_write.hh"
20
23
24#include <fmt/format.h>
25
27
29
31{
32 b.add_input<decl::Bundle>("Bundle");
33 const bNodeTree *tree = b.tree_or_null();
34 const bNode *node = b.node_or_null();
35 if (tree && node) {
36 const NodeSeparateBundle &storage = node_storage(*node);
37 for (const int i : IndexRange(storage.items_num)) {
38 const NodeSeparateBundleItem &item = storage.items[i];
39 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
40 const StringRef name = item.name ? item.name : "";
41 const std::string identifier = SeparateBundleItemsAccessor::socket_identifier_for_item(item);
42 auto &decl = b.add_output(socket_type, name, identifier)
43 .socket_name_ptr(
45 .propagate_all()
46 .reference_pass_all();
48 decl.structure_type(StructureType(item.structure_type));
49 }
50 else {
51 decl.structure_type(StructureType::Dynamic);
52 }
53 }
54 }
55 b.add_output<decl::Extend>("", "__extend__");
56}
57
58static void node_init(bNodeTree * /*tree*/, bNode *node)
59{
60 auto *storage = MEM_callocN<NodeSeparateBundle>(__func__);
61 node->storage = storage;
62}
63
64static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
65{
66 const NodeSeparateBundle &src_storage = node_storage(*src_node);
67 auto *dst_storage = MEM_dupallocN<NodeSeparateBundle>(__func__, src_storage);
68 dst_node->storage = dst_storage;
69
71}
72
78
80{
81 if (params.C && params.link.tonode == &params.node && params.link.fromsock->type == SOCK_BUNDLE)
82 {
83 const NodeSeparateBundle &storage = node_storage(params.node);
84 if (storage.items_num == 0) {
86 if (snode && snode->edittree == &params.ntree) {
87 sync_sockets_separate_bundle(*snode, params.node, nullptr, params.link.fromsock);
88 }
89 }
90 return true;
91 }
93 params.ntree, params.node, params.node, params.link);
94}
95
96static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *node_ptr)
97{
98 bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(node_ptr->owner_id);
99 bNode &node = *static_cast<bNode *>(node_ptr->data);
100
101 layout->use_property_split_set(true);
102 layout->use_property_decorate_set(false);
103
104 layout->op("node.sockets_sync", IFACE_("Sync"), ICON_FILE_REFRESH);
105 layout->prop(node_ptr, "define_signature", UI_ITEM_NONE, std::nullopt, ICON_NONE);
106 if (uiLayout *panel = layout->panel(C, "bundle_items", false, IFACE_("Bundle Items"))) {
108 C, panel, ntree, node);
110 ntree, node, [&](PointerRNA *item_ptr) {
111 const auto &item = *item_ptr->data_as<NodeSeparateBundleItem>();
112 panel->use_property_split_set(true);
113 panel->use_property_decorate_set(false);
114 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, IFACE_("Type"), ICON_NONE);
115 if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
116 panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, IFACE_("Shape"), ICON_NONE);
117 }
118 });
119 }
120}
121
126
128{
129 nodes::BundlePtr bundle = params.extract_input<nodes::BundlePtr>("Bundle");
130 if (!bundle) {
131 params.set_default_remaining_outputs();
132 return;
133 }
134
135 const bNode &node = params.node();
136 const NodeSeparateBundle &storage = node_storage(node);
137
138 lf::Params &lf_params = params.low_level_lazy_function_params();
139
140 for (const int i : IndexRange(storage.items_num)) {
141 const NodeSeparateBundleItem &item = storage.items[i];
142 const StringRef name = item.name;
143 if (name.is_empty()) {
144 continue;
145 }
147 if (!stype || !stype->geometry_nodes_default_value) {
148 continue;
149 }
150 const BundleItemValue *value = bundle->lookup(name);
151 if (!value) {
152 params.error_message_add(
154 fmt::format(fmt::runtime(TIP_("Value not found in bundle: \"{}\"")), name));
155 continue;
156 }
157 const auto *socket_value = std::get_if<BundleItemSocketValue>(&value->value);
158 if (!socket_value) {
159 params.error_message_add(
161 fmt::format("{}: \"{}\"", TIP_("Cannot get internal value from bundle"), name));
162 continue;
163 }
164
165 SocketValueVariant output_value = std::move(socket_value->value);
166 if (socket_value->type->type != stype->type) {
167 if (std::optional<SocketValueVariant> converted_value = implicitly_convert_socket_value(
168 *socket_value->type, output_value, *stype))
169 {
170 output_value = std::move(*converted_value);
171 params.error_message_add(
173 fmt::format("{}: \"{}\" ({} " BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE " {})",
174 TIP_("Implicit type conversion when separating bundle"),
175 name,
176 TIP_(socket_value->type->label),
177 TIP_(stype->label)));
178 }
179 else {
180 params.error_message_add(
182 fmt::format("{}: \"{}\" ({} " BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE " {})",
183 TIP_("Conversion not supported when separating bundle"),
184 name,
185 TIP_(socket_value->type->label),
186 TIP_(stype->label)));
187 output_value = *stype->geometry_nodes_default_value;
188 }
189 }
190 lf_params.set_output(i, std::move(output_value));
191 }
192
193 params.set_default_remaining_outputs();
194}
195
197{
198 const bNodeSocket &other_socket = params.other_socket();
199 if (other_socket.in_out == SOCK_IN) {
201 params.node_tree().type))
202 {
203 return;
204 }
205 params.add_item(IFACE_("Item"), [](LinkSearchOpParams &params) {
206 bNode &node = params.add_node("NodeSeparateBundle");
207 const auto *item =
209 params.node_tree, node, params.socket.typeinfo->type, params.socket.name);
210 params.update_and_connect_available_socket(node, item->name);
211 });
212 }
213 else {
214 if (other_socket.type != SOCK_BUNDLE) {
215 return;
216 }
217 params.add_item(IFACE_("Bundle"), [](LinkSearchOpParams &params) {
218 bNode &node = params.add_node("NodeSeparateBundle");
219 params.connect_available_socket(node, "Bundle");
220
221 SpaceNode &snode = *CTX_wm_space_node(&params.C);
222 sync_sockets_separate_bundle(snode, node, nullptr);
223 });
224 }
225}
226
227static void node_blend_write(const bNodeTree & /*tree*/, const bNode &node, BlendWriter &writer)
228{
230}
231
232static void node_blend_read(bNodeTree & /*tree*/, bNode &node, BlendDataReader &reader)
233{
235}
236
237static void node_register()
238{
239 static blender::bke::bNodeType ntype;
240
241 sh_geo_node_type_base(&ntype, "NodeSeparateBundle", NODE_SEPARATE_BUNDLE);
242 ntype.ui_name = "Separate Bundle";
243 ntype.ui_description = "Split a bundle into multiple sockets.";
245 ntype.declare = node_declare;
246 ntype.initfunc = node_init;
254 bke::node_type_storage(ntype, "NodeSeparateBundle", node_free_storage, node_copy_storage);
256}
258
259} // namespace blender::nodes::node_geo_separate_bundle_cc
260
261namespace blender::nodes {
262
263StructRNA *SeparateBundleItemsAccessor::item_srna = &RNA_NodeSeparateBundleItem;
264
266{
267 BLO_write_string(writer, item.name);
268}
269
274
275} // namespace blender::nodes
SpaceNode * CTX_wm_space_node(const bContext *C)
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:453
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define NODE_SEPARATE_BUNDLE
#define BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5828
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define TIP_(msgid)
#define IFACE_(msgid)
@ NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_BUNDLE
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define C
Definition RandGen.cpp:29
#define UI_ITEM_NONE
void set_output(int index, T &&value)
KDTree_3d * tree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
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 node_register_type(bNodeType &ntype)
Definition node.cc:2416
bNodeSocketType * node_socket_type_find_static(int type, int subtype=0)
Definition node.cc:2471
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))
Definition node.cc:5414
static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
static void node_blend_write(const bNodeTree &, const bNode &node, BlendWriter &writer)
static bool node_insert_link(bke::NodeInsertLinkParams &params)
static void node_init(bNodeTree *, bNode *node)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *node_ptr)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_blend_read(bNodeTree &, bNode &node, BlendDataReader &reader)
static void draw_items_list_with_operators(const bContext *C, uiLayout *layout, const bNodeTree &tree, const bNode &node)
static void draw_active_item_props(const bNodeTree &tree, const bNode &node, const FunctionRef< void(PointerRNA *item_ptr)> draw_item)
void blend_write(BlendWriter *writer, const bNode &node)
void blend_read_data(BlendDataReader *reader, bNode &node)
void copy_array(const bNode &src_node, bNode &dst_node)
Accessor::ItemT * add_item_with_socket_type_and_name(bNodeTree &ntree, bNode &node, const eNodeSocketDatatype socket_type, const char *name, std::optional< int > dimensions=std::nullopt)
bool try_add_item_via_any_extend_socket(bNodeTree &ntree, bNode &extend_node, bNode &storage_node, bNodeLink &link, const std::optional< StringRef > socket_identifier=std::nullopt, typename Accessor::ItemT **r_new_item=nullptr)
ImplicitSharingPtr< Bundle > BundlePtr
void sync_sockets_separate_bundle(SpaceNode &snode, bNode &separate_bundle_node, ReportList *reports, const bNodeSocket *src_bundle_socket)
std::optional< SocketValueVariant > implicitly_convert_socket_value(const bke::bNodeSocketType &from_type, const SocketValueVariant &from_value, const bke::bNodeSocketType &to_type)
bool socket_type_always_single(const eNodeSocketDatatype socket_type)
void sh_geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
const char * name
NodeSeparateBundleItem * items
T * data_as() const
Definition RNA_types.hh:124
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
struct bNodeTree * edittree
bNodeSocketTypeHandle * typeinfo
char name[64]
void * storage
Defines a socket type.
Definition BKE_node.hh:158
eNodeSocketDatatype type
Definition BKE_node.hh:193
const SocketValueVariant * geometry_nodes_default_value
Definition BKE_node.hh:211
Defines a node type.
Definition BKE_node.hh:238
NodeBlendWriteFunction blend_write_storage_content
Definition BKE_node.hh:390
std::string ui_description
Definition BKE_node.hh:244
NodeBlendDataReadFunction blend_data_read_storage_content
Definition BKE_node.hh:391
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:261
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
bool(* insert_link)(NodeInsertLinkParams &params)
Definition BKE_node.hh:333
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* register_operators)()
Definition BKE_node.hh:417
std::variant< BundleItemSocketValue, BundleItemInternalValue > value
static bool supports_socket_type(const eNodeSocketDatatype socket_type, const int ntree_type)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
static void blend_read_data_item(BlendDataReader *reader, ItemT &item)
static std::string socket_identifier_for_item(const ItemT &item)
void use_property_decorate_set(bool is_sep)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230