Blender V5.0
node_geo_viewer.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 <fmt/format.h>
6
7#include "BKE_context.hh"
9
10#include "BLO_read_write.hh"
11
12#include "DNA_modifier_types.h"
13
14#include "NOD_geo_viewer.hh"
20
22#include "UI_resources.hh"
23
24#include "ED_node.hh"
25#include "ED_viewer_path.hh"
26
27#include "RNA_enum_types.hh"
28#include "RNA_prototypes.hh"
29
31
32#include "node_geometry_util.hh"
33
35
37
38static void draw_float(uiLayout &layout, const float value)
39{
40 const std::string label = fmt::format("{:.5f}", value);
41 layout.label(label, ICON_NONE);
42}
43static void draw_int(uiLayout &layout, const int value)
44{
45 const std::string label = fmt::format("{}", value);
46 layout.label(label, ICON_NONE);
47}
48static void draw_bool(uiLayout &layout, const bool value)
49{
50 layout.label(value ? IFACE_("True") : IFACE_("False"), ICON_NONE);
51}
52static void draw_vector(uiLayout &layout, const float3 &value)
53{
54 uiLayout &col = layout.column(true);
55 col.label(fmt::format("{}: {:.5f}", IFACE_("X"), value.x), ICON_NONE);
56 col.label(fmt::format("{}: {:.5f}", IFACE_("Y"), value.y), ICON_NONE);
57 col.label(fmt::format("{}: {:.5f}", IFACE_("Z"), value.z), ICON_NONE);
58}
59static void draw_color(uiLayout &layout, const ColorGeometry4f &value)
60{
61 uiLayout &col = layout.column(true);
62 col.label(fmt::format("{}: {:.5f}", CTX_IFACE_(BLT_I18NCONTEXT_COLOR, "R"), value.r), ICON_NONE);
63 col.label(fmt::format("{}: {:.5f}", CTX_IFACE_(BLT_I18NCONTEXT_COLOR, "G"), value.g), ICON_NONE);
64 col.label(fmt::format("{}: {:.5f}", CTX_IFACE_(BLT_I18NCONTEXT_COLOR, "B"), value.b), ICON_NONE);
65 col.label(fmt::format("{}: {:.5f}", CTX_IFACE_(BLT_I18NCONTEXT_COLOR, "A"), value.a), ICON_NONE);
66}
67static void draw_string(uiLayout &layout, const StringRef value)
68{
69 /* The node doesn't get wider than that anyway. */
70 const int max_display_length = 200;
71 layout.label(value.substr(0, max_display_length), ICON_NONE);
72}
75{
76 tree_log.ensure_viewer_node_logs();
77 geo_eval_log::ViewerNodeLog *viewer_log = tree_log.viewer_node_logs.lookup_default(
78 params.node.identifier, nullptr);
79 if (!viewer_log) {
80 return false;
81 }
82 const int socket_index = params.socket.index();
83 const auto &storage = *static_cast<NodeGeometryViewer *>(params.node.storage);
84 const NodeGeometryViewerItem &viewer_item = storage.items[socket_index];
85 const geo_eval_log::ViewerNodeLog::Item *item_log = viewer_log->items.lookup_key_ptr_as(
86 viewer_item.identifier);
87 if (!item_log) {
88 return false;
89 }
90 const bke::SocketValueVariant &value = item_log->value;
91 if (!value.is_single()) {
92 return false;
93 }
94 const GPointer single_value = value.get_single_ptr();
95 if (single_value.is_type<float>()) {
96 draw_float(params.layout, *single_value.get<float>());
97 return true;
98 }
99 if (single_value.is_type<float3>()) {
100 draw_vector(params.layout, *single_value.get<float3>());
101 return true;
102 }
103 if (single_value.is_type<int>()) {
104 draw_int(params.layout, *single_value.get<int>());
105 return true;
106 }
107 if (single_value.is_type<bool>()) {
108 draw_bool(params.layout, *single_value.get<bool>());
109 return true;
110 }
111 if (single_value.is_type<std::string>()) {
112 draw_string(params.layout, *single_value.get<std::string>());
113 return true;
114 }
115 if (single_value.is_type<ColorGeometry4f>()) {
116 draw_color(params.layout, *single_value.get<ColorGeometry4f>());
117 return true;
118 }
119 return false;
120}
122{
123 const CPPType &value_type = *params.socket.typeinfo->base_cpp_type;
124 const CPPType &socket_base_cpp_type = *params.socket.typeinfo->base_cpp_type;
126 if (value_type != socket_base_cpp_type) {
127 if (!conversions.is_convertible(value_type, socket_base_cpp_type)) {
128 return false;
129 }
130 }
131 BUFFER_FOR_CPP_TYPE_VALUE(socket_base_cpp_type, socket_value);
132 conversions.convert_to_uninitialized(
133 value_type, socket_base_cpp_type, value.get(), socket_value);
134 BLI_SCOPED_DEFER([&]() { socket_base_cpp_type.destruct(socket_value); });
135 switch (params.socket.type) {
136 case SOCK_INT:
137 draw_int(params.layout, *static_cast<int *>(socket_value));
138 return true;
139 case SOCK_FLOAT:
140 draw_float(params.layout, *static_cast<float *>(socket_value));
141 return true;
142 case SOCK_VECTOR:
143 draw_vector(params.layout, *static_cast<float3 *>(socket_value));
144 return true;
145 case SOCK_RGBA:
146 draw_color(params.layout, *static_cast<ColorGeometry4f *>(socket_value));
147 return true;
148 case SOCK_BOOLEAN:
149 draw_bool(params.layout, *static_cast<bool *>(socket_value));
150 return true;
151 default:
152 return false;
153 }
154 return false;
155}
157 geo_eval_log::GeoTreeLog &tree_log)
158{
159 tree_log.ensure_socket_values();
160 geo_eval_log::ValueLog *value_log = tree_log.find_socket_value_log(params.socket);
161 if (!value_log) {
162 return false;
163 }
164 if (const auto *generic_value_log = dynamic_cast<const geo_eval_log::GenericValueLog *>(
165 value_log))
166 {
167 return draw_generic_value_log(params, generic_value_log->value);
168 }
169 if (const auto *string_value_log = dynamic_cast<const geo_eval_log::StringLog *>(value_log)) {
170 draw_string(params.layout, string_value_log->value);
171 return true;
172 }
173 return false;
174}
176{
178 if (!snode) {
179 params.draw_standard(params.layout);
180 return;
181 }
182 snode->edittree->ensure_topology_cache();
183 const bNodeSocket &socket = params.socket;
184 if (!socket.is_directly_linked()) {
185 params.draw_standard(params.layout);
186 return;
187 }
188 const geo_eval_log::ContextualGeoTreeLogs geo_tree_logs =
190 geo_eval_log::GeoTreeLog *tree_log = geo_tree_logs.get_main_tree_log(params.node);
191 if (!tree_log) {
192 params.draw_standard(params.layout);
193 return;
194 }
195 if (draw_from_viewer_log_value(params, *tree_log)) {
196 return;
197 }
198 if (draw_from_socket_log_value(params, *tree_log)) {
199 return;
200 }
201 params.draw_standard(params.layout);
202}
203
205{
206 b.use_custom_socket_order();
207 b.allow_any_socket_order();
208
209 const bNode *node = b.node_or_null();
210 const bNodeTree *tree = b.tree_or_null();
211
212 if (!node || !tree) {
213 return;
214 }
215
216 b.add_default_layout();
217
218 const NodeGeometryViewer &storage = node_storage(*node);
219 for (const int i : IndexRange(storage.items_num)) {
220 const NodeGeometryViewerItem &item = storage.items[i];
221 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
222 const StringRef name = item.name ? item.name : "";
223 const std::string identifier = GeoViewerItemsAccessor::socket_identifier_for_item(item);
224 auto &input_decl = b.add_input(socket_type, name, identifier)
225 .socket_name_ptr(
226 &tree->id, GeoViewerItemsAccessor::item_srna, &item, "name");
227 if (socket_type_supports_fields(socket_type)) {
228 input_decl.field_on_all();
229 }
230 input_decl.structure_type(StructureType::Dynamic);
231 input_decl.custom_draw([](CustomSocketDrawParams &params) { draw_input_socket(params); });
232 }
233
234 b.add_input<decl::Extend>("", "__extend__").structure_type(StructureType::Dynamic);
235}
236
237static void node_init(bNodeTree * /*tree*/, bNode *node)
238{
240 data->data_type_legacy = CD_PROP_FLOAT;
241 data->domain = int8_t(AttrDomain::Auto);
242 node->storage = data;
243}
244
245static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
246{
247 const bNode &node = *ptr->data_as<bNode>();
248 const NodeGeometryViewer &storage = node_storage(node);
249
250 bool has_geometry_input = false;
251 bool has_potential_field_input = false;
252 for (const int i : IndexRange(storage.items_num)) {
253 const NodeGeometryViewerItem &item = storage.items[i];
254 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
255 if (socket_type == SOCK_GEOMETRY) {
256 has_geometry_input = true;
257 }
258 else if (socket_type_supports_fields(socket_type)) {
259 has_potential_field_input = true;
260 }
261 }
262
263 if (has_geometry_input && has_potential_field_input) {
264 layout->prop(ptr, "domain", UI_ITEM_NONE, "", ICON_NONE);
265 }
266}
267
269{
270 bNode &node = *ptr->data_as<bNode>();
271 bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
272
273 if (uiLayout *panel = layout->panel(C, "viewer_items", false, IFACE_("Viewer Items"))) {
275 C, panel, ntree, node);
277 ntree, node, [&](PointerRNA *item_ptr) {
278 panel->use_property_split_set(true);
279 panel->use_property_decorate_set(false);
280 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
281 panel->prop(item_ptr, "auto_remove", UI_ITEM_NONE, std::nullopt, ICON_NONE);
282 });
283 }
284}
285
287{
288 const bNodeSocket &other_socket = params.other_socket();
289 if (other_socket.in_out == SOCK_OUT) {
290 params.add_item(IFACE_("Value"), [](LinkSearchOpParams &params) {
291 bNode &node = params.add_node("GeometryNodeViewer");
293 params.node_tree, node, params.socket.typeinfo->type, params.socket.name);
294 params.update_and_connect_available_socket(node, item->name);
296 Main *bmain = CTX_data_main(&params.C);
297 ed::viewer_path::activate_geometry_node(*bmain, *snode, node);
298 });
299 return;
300 }
301}
302
308{
309 const auto &storage = *static_cast<NodeGeometryViewer *>(node.storage);
310 const StringRef viewer_attribute_name = ".viewer";
311 std::optional<int> last_geometry_identifier;
312 for (const int i : IndexRange(storage.items_num)) {
313 const bNodeSocket &bsocket = node.input_socket(i);
314 const NodeGeometryViewerItem &item = storage.items[i];
315 const bke::bNodeSocketType &type = *bsocket.typeinfo;
316
317 if (type.type == SOCK_GEOMETRY) {
318 last_geometry_identifier = item.identifier;
319 continue;
320 }
321 if (!last_geometry_identifier) {
322 continue;
323 }
325 continue;
326 }
327 /* Changing the `value` field doesn't change the hash or equality of the item. */
328 GMutablePointer geometry_ptr = const_cast<bke::SocketValueVariant &>(
329 r_log.items.lookup_key_as(*last_geometry_identifier).value)
331 GeometrySet &geometry = *geometry_ptr.get<GeometrySet>();
332 const bke::SocketValueVariant &value = r_log.items.lookup_key_as(item.identifier).value;
333 if (!(value.is_single() || value.is_context_dependent_field())) {
334 continue;
335 }
336 const GField field = value.get<GField>();
337 const AttrDomain domain_or_auto = AttrDomain(storage.domain);
338 if (domain_or_auto == AttrDomain::Instance) {
339 if (geometry.has_instances()) {
340 bke::GeometryComponent &component =
341 geometry.get_component_for_write<bke::InstancesComponent>();
343 component, viewer_attribute_name, AttrDomain::Instance, field);
344 }
345 }
346 else {
348 for (const bke::GeometryComponent::Type type :
353 {
354 if (!geometry.has(type)) {
355 continue;
356 }
357 bke::GeometryComponent &component = geometry.get_component_for_write(type);
358 AttrDomain used_domain = domain_or_auto;
359 if (domain_or_auto == AttrDomain::Auto) {
360 if (const std::optional<AttrDomain> domain = bke::try_detect_field_domain(component,
361 field))
362 {
363 used_domain = *domain;
364 }
365 else {
366 used_domain = AttrDomain::Point;
367 }
368 }
369 bke::try_capture_field_on_geometry(component, viewer_attribute_name, used_domain, field);
370 }
371 });
372 }
373 /* Avoid overriding the viewer attribute with other fields.*/
374 last_geometry_identifier.reset();
375 }
376}
377
378static void geo_viewer_node_log_impl(const bNode &node,
379 const Span<bke::SocketValueVariant *> input_values,
381{
382 const auto &storage = *static_cast<NodeGeometryViewer *>(node.storage);
383 for (const int i : IndexRange(storage.items_num)) {
384 void *src_value = input_values[i];
385 if (!src_value) {
386 continue;
387 }
388 const NodeGeometryViewerItem &item = storage.items[i];
389
390 bke::SocketValueVariant &value = *input_values[i];
391 if (value.is_single() && value.get_single_ptr().is_type<bke::GeometrySet>()) {
392 value.get_single_ptr().get<bke::GeometrySet>()->ensure_owns_direct_data();
393 }
394 r_log.items.add_new({item.identifier, item.name, std::move(value)});
395 }
396 log_viewer_attribute(node, r_log);
397}
398
400{
402 if (snode) {
403 if (std::optional<ed::space_node::ObjectAndModifier> object_and_modifier =
405 {
406 const NodesModifierData &nmd = *object_and_modifier->nmd;
407 nmd.node_group->ensure_topology_cache();
408 if (!(nmd.modifier.mode & eModifierMode_Realtime)) {
410 row.icon = ICON_ERROR;
411 row.text = TIP_("Modifier disabled");
412 row.tooltip = TIP_("The viewer does not work because the modifier is disabled");
413 params.rows.append(std::move(row));
414 }
415 else if (!nmd.node_group->group_output_node()) {
417 row.icon = ICON_ERROR;
418 row.text = TIP_("Missing output");
419 row.tooltip = TIP_(
420 "The viewer does not work because the node group used by the modifier has no output");
421 params.rows.append(std::move(row));
422 }
423 }
424 }
425 const auto data_type = eCustomDataType(node_storage(params.node).data_type_legacy);
426 if (ELEM(data_type, CD_PROP_QUATERNION, CD_PROP_FLOAT4X4)) {
428 row.icon = ICON_INFO;
429 row.text = TIP_("No color overlay");
430 row.tooltip = TIP_(
431 "Rotation values can only be displayed with the text overlay in the 3D view");
432 params.rows.append(std::move(row));
433 }
434}
435
440
446
447static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
448{
449 const NodeGeometryViewer &src_storage = node_storage(*src_node);
450 auto *dst_storage = MEM_mallocN<NodeGeometryViewer>(__func__);
451 *dst_storage = src_storage;
452 dst_node->storage = dst_storage;
453
455}
456
458{
459 NodeGeometryViewerItem *new_item = nullptr;
461 params.ntree, params.node, params.node, params.link, std::nullopt, &new_item);
462 if (new_item) {
464 }
465 return keep_link;
466}
467
468static void node_blend_write(const bNodeTree & /*tree*/, const bNode &node, BlendWriter &writer)
469{
471}
472
473static void node_blend_read(bNodeTree & /*tree*/, bNode &node, BlendDataReader &reader)
474{
476}
477
478static void node_register()
479{
480 static blender::bke::bNodeType ntype;
481
482 geo_node_type_base(&ntype, "GeometryNodeViewer", GEO_NODE_VIEWER);
483 ntype.ui_name = "Viewer";
484 ntype.ui_description = "Display the input data in the Spreadsheet Editor";
485 ntype.enum_name_legacy = "VIEWER";
488 ntype, "NodeGeometryViewer", node_free_storage, node_copy_storage);
489 ntype.declare = node_declare;
490 ntype.initfunc = node_init;
495 ntype.no_muting = true;
501}
503
504} // namespace blender::nodes::node_geo_viewer_cc
505
506namespace blender::nodes {
507
508StructRNA *GeoViewerItemsAccessor::item_srna = &RNA_NodeGeometryViewerItem;
509
511 const NodeGeometryViewerItem &item)
512{
513 BLO_write_string(writer, item.name);
514}
515
521
522void geo_viewer_node_log(const bNode &node,
523 const Span<bke::SocketValueVariant *> input_values,
525{
526 node_geo_viewer_cc::geo_viewer_node_log_impl(node, input_values, r_log);
527}
528
529} // namespace blender::nodes
SpaceNode * CTX_wm_space_node(const bContext *C)
Main * CTX_data_main(const bContext *C)
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:448
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define GEO_NODE_VIEWER
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
#define BLI_SCOPED_DEFER(function_to_defer)
#define ELEM(...)
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 CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_COLOR
@ CD_PROP_FLOAT
@ CD_PROP_QUATERNION
@ CD_PROP_FLOAT4X4
@ eModifierMode_Realtime
@ SOCK_OUT
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_FLOAT
@ SOCK_GEOMETRY
@ SOCK_RGBA
@ NODE_GEO_VIEWER_ITEM_FLAG_AUTO_REMOVE
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define C
Definition RandGen.cpp:29
#define UI_ITEM_NONE
BMesh const char void * data
void destruct(void *ptr) const
ChannelStorageType r
ChannelStorageType g
ChannelStorageType b
ChannelStorageType a
const void * get() const
constexpr StringRef substr(int64_t start, int64_t size) const
void convert_to_uninitialized(const CPPType &from_type, const CPPType &to_type, const void *from_value, void *to_value) const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
GeoTreeLog * get_main_tree_log(const bke::bNodeTreeZone *zone) const
static ContextualGeoTreeLogs get_contextual_tree_logs(const SpaceNode &snode)
Map< int32_t, ViewerNodeLog *, 0 > viewer_node_logs
ValueLog * find_socket_value_log(const bNodeSocket &query_socket)
CustomIDVectorSet< Item, ItemIdentifierGetter > items
KDTree_3d * tree
uint col
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
std::optional< AttrDomain > try_detect_field_domain(const GeometryComponent &component, const fn::GField &field)
const DataTypeConversions & get_implicit_type_conversions()
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
bool try_capture_field_on_geometry(MutableAttributeAccessor attributes, const fn::FieldContext &field_context, const StringRef attribute_id, AttrDomain domain, const fn::Field< bool > &selection, const fn::GField &field)
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
std::optional< ObjectAndModifier > get_modifier_for_node_editor(const SpaceNode &snode)
void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node, std::optional< int > item_identifier=std::nullopt)
void foreach_real_geometry(bke::GeometrySet &geometry, FunctionRef< void(bke::GeometrySet &geometry_set)> fn)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
static bool node_insert_link(bke::NodeInsertLinkParams &params)
static void draw_input_socket(CustomSocketDrawParams &params)
static void node_blend_write(const bNodeTree &, const bNode &node, BlendWriter &writer)
static void draw_vector(uiLayout &layout, const float3 &value)
static bool draw_from_viewer_log_value(CustomSocketDrawParams &params, geo_eval_log::GeoTreeLog &tree_log)
static void draw_bool(uiLayout &layout, const bool value)
static bool draw_from_socket_log_value(CustomSocketDrawParams &params, geo_eval_log::GeoTreeLog &tree_log)
static void draw_float(uiLayout &layout, const float value)
static void node_blend_read(bNodeTree &, bNode &node, BlendDataReader &reader)
static void draw_int(uiLayout &layout, const int value)
static void draw_color(uiLayout &layout, const ColorGeometry4f &value)
static bool draw_generic_value_log(CustomSocketDrawParams &params, const GPointer &value)
static void node_free_storage(bNode *node)
static void geo_viewer_node_log_impl(const bNode &node, const Span< bke::SocketValueVariant * > input_values, geo_eval_log::ViewerNodeLog &r_log)
static void log_viewer_attribute(const bNode &node, geo_eval_log::ViewerNodeLog &r_log)
static void node_init(bNodeTree *, bNode *node)
static void draw_string(uiLayout &layout, const StringRef value)
static void node_declare(NodeDeclarationBuilder &b)
static void node_extra_info(NodeExtraInfoParams &params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
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)
void geo_viewer_node_log(const bNode &node, const Span< bke::SocketValueVariant * > input_values, geo_eval_log::ViewerNodeLog &r_log)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
const char * name
NodeGeometryViewerItem * items
struct bNodeTree * node_group
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
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
NodeExtraInfoFunction get_extra_info
Definition BKE_node.hh:381
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
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
static void blend_read_data_item(BlendDataReader *reader, ItemT &item)
static std::string socket_identifier_for_item(const NodeGeometryViewerItem &item)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
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
PointerRNA * ptr
Definition wm_files.cc:4238