Blender V5.0
node_geo_switch.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
6
8
10#include "UI_resources.hh"
11
12#include "NOD_rna_define.hh"
13#include "NOD_socket.hh"
15
16#include "RNA_enum_types.hh"
17
19
21
23
25{
26 auto &switch_decl = b.add_input<decl::Bool>("Switch");
27 const bNode *node = b.node_or_null();
28 if (!node) {
29 return;
30 }
31 const NodeSwitch &storage = node_storage(*node);
32 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(storage.input_type);
33
34 auto &false_decl = b.add_input(socket_type, "False");
35 auto &true_decl = b.add_input(socket_type, "True");
36 auto &output_decl = b.add_output(socket_type, "Output");
37
38 if (socket_type_supports_fields(socket_type)) {
39 switch_decl.supports_field();
40 false_decl.supports_field();
41 true_decl.supports_field();
42 output_decl.dependent_field().reference_pass_all();
43 }
45 output_decl.propagate_all();
46 }
48 output_decl.reference_pass_all();
49 }
50
51 const StructureType structure_type = socket_type_always_single(socket_type) ?
52 StructureType::Single :
53 StructureType::Dynamic;
54
55 switch_decl.structure_type(structure_type);
56 false_decl.structure_type(structure_type);
57 true_decl.structure_type(structure_type);
58 output_decl.structure_type(structure_type);
59}
60
61static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
62{
63 layout->prop(ptr, "input_type", UI_ITEM_NONE, "", ICON_NONE);
64}
65
66static void node_init(bNodeTree * /*tree*/, bNode *node)
67{
69 data->input_type = SOCK_GEOMETRY;
70 node->storage = data;
71}
72
74{
75 if (params.in_out() == SOCK_OUT) {
76 params.add_item(IFACE_("Output"), [](LinkSearchOpParams &params) {
77 bNode &node = params.add_node("GeometryNodeSwitch");
78 node_storage(node).input_type = params.socket.type;
79 params.update_and_connect_available_socket(node, "Output");
80 });
81 }
82 else {
83 /* Make sure the switch input comes first in the search for boolean sockets. */
84 int true_false_weights = 0;
85 if (params.other_socket().type == SOCK_BOOLEAN) {
86 params.add_item(IFACE_("Switch"), [](LinkSearchOpParams &params) {
87 bNode &node = params.add_node("GeometryNodeSwitch");
88 params.update_and_connect_available_socket(node, "Switch");
89 });
90 true_false_weights--;
91 }
92
93 params.add_item(
94 IFACE_("False"),
96 bNode &node = params.add_node("GeometryNodeSwitch");
97 node_storage(node).input_type = params.socket.type;
98 params.update_and_connect_available_socket(node, "False");
99 },
100 true_false_weights);
101 params.add_item(
102 IFACE_("True"),
104 bNode &node = params.add_node("GeometryNodeSwitch");
105 node_storage(node).input_type = params.socket.type;
106 params.update_and_connect_available_socket(node, "True");
107 },
108 true_false_weights);
109 }
110}
111
113 private:
114 bool can_be_field_ = false;
115 const CPPType *base_type_;
116
117 public:
119 {
120 const NodeSwitch &storage = node_storage(node);
121 const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.input_type);
122 can_be_field_ = socket_type_supports_fields(data_type);
123
124 const bke::bNodeSocketType *socket_type = nullptr;
125 for (const bNodeSocket *socket : node.output_sockets()) {
126 if (socket->type == data_type) {
127 socket_type = socket->typeinfo;
128 break;
129 }
130 }
131 BLI_assert(socket_type != nullptr);
132 const CPPType &cpp_type = CPPType::get<SocketValueVariant>();
133 base_type_ = socket_type->base_cpp_type;
134
135 debug_name_ = node.name;
136 inputs_.append_as("Condition", CPPType::get<SocketValueVariant>());
137 inputs_.append_as("False", cpp_type, lf::ValueUsage::Maybe);
138 inputs_.append_as("True", cpp_type, lf::ValueUsage::Maybe);
139 outputs_.append_as("Value", cpp_type);
140 }
141
142 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
143 {
144 SocketValueVariant condition_variant = params.get_input<SocketValueVariant>(0);
145 if (condition_variant.is_context_dependent_field() && can_be_field_) {
146 this->execute_field(condition_variant.get<Field<bool>>(), params);
147 }
148 else {
149 this->execute_single(condition_variant.get<bool>(), params);
150 }
151 }
152
153 static constexpr int false_input_index = 1;
154 static constexpr int true_input_index = 2;
155
156 void execute_single(const bool condition, lf::Params &params) const
157 {
158 const int input_to_forward = condition ? true_input_index : false_input_index;
159 const int input_to_ignore = condition ? false_input_index : true_input_index;
160
161 params.set_input_unused(input_to_ignore);
162 void *value_to_forward = params.try_get_input_data_ptr_or_request(input_to_forward);
163 if (value_to_forward == nullptr) {
164 /* Try again when the value is available. */
165 return;
166 }
167
168 const CPPType &type = *outputs_[0].type;
169 void *output_ptr = params.get_output_data_ptr(0);
170 type.move_construct(value_to_forward, output_ptr);
171 params.output_set(0);
172 }
173
175 {
176 /* When the condition is a non-constant field, we need both inputs. */
177 auto *false_value_variant = params.try_get_input_data_ptr_or_request<SocketValueVariant>(
179 auto *true_value_variant = params.try_get_input_data_ptr_or_request<SocketValueVariant>(
181 if (ELEM(nullptr, false_value_variant, true_value_variant)) {
182 /* Try again when inputs are available. */
183 return;
184 }
185
186 const MultiFunction &switch_multi_function = this->get_switch_multi_function();
187
188 GField false_field = false_value_variant->extract<GField>();
189 GField true_field = true_value_variant->extract<GField>();
190
191 GField output_field{FieldOperation::from(
192 switch_multi_function,
193 {std::move(condition), std::move(false_field), std::move(true_field)})};
194
195 void *output_ptr = params.get_output_data_ptr(0);
196 SocketValueVariant::ConstructIn(output_ptr, std::move(output_field));
197 params.output_set(0);
198 }
199
200 const MultiFunction &get_switch_multi_function() const
201 {
202 const MultiFunction *switch_multi_function = nullptr;
203 base_type_->to_static_type_tag<float,
204 int,
205 bool,
206 float3,
208 std::string,
210 float4x4,
211 MenuValue>([&](auto type_tag) {
212 using T = typename decltype(type_tag)::type;
213 if constexpr (std::is_void_v<T>) {
215 }
216 else {
217 static auto switch_fn = mf::build::SI3_SO<bool, T, T, T>(
218 "Switch", [](const bool condition, const T &false_value, const T &true_value) {
219 return condition ? true_value : false_value;
220 });
221 switch_multi_function = &switch_fn;
222 }
223 });
224 BLI_assert(switch_multi_function != nullptr);
225 return *switch_multi_function;
226 }
227};
228
230 const bNode &node,
231 const bNodeSocket & /*output_socket*/)
232{
233 /* Default to the False input. */
234 return &node.input_socket(1);
235}
236
237static void node_rna(StructRNA *srna)
238{
240 srna,
241 "input_type",
242 "Input Type",
243 "",
245 NOD_storage_enum_accessors(input_type),
247 [](bContext * /*C*/, PointerRNA * /*ptr*/, PropertyRNA * /*prop*/, bool *r_free) {
248 *r_free = true;
250 [](const EnumPropertyItem &item) -> bool {
251 return ELEM(item.value,
253 SOCK_INT,
259 SOCK_RGBA,
265 SOCK_MENU,
268 });
269 });
270}
271
272static void register_node()
273{
274 static blender::bke::bNodeType ntype;
275
276 geo_node_type_base(&ntype, "GeometryNodeSwitch", GEO_NODE_SWITCH);
277 ntype.ui_name = "Switch";
278 ntype.ui_description = "Switch between two inputs";
279 ntype.enum_name_legacy = "SWITCH";
281 ntype.declare = node_declare;
282 ntype.initfunc = node_init;
290
291 node_rna(ntype.rna_ext.srna);
292}
294
295} // namespace blender::nodes::node_geo_switch_cc
296
297namespace blender::nodes {
298
299std::unique_ptr<LazyFunction> get_switch_node_lazy_function(const bNode &node)
300{
301 using namespace node_geo_switch_cc;
303 return std::make_unique<LazyFunctionForSwitchNode>(node);
304}
305
306} // namespace blender::nodes
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:453
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define GEO_NODE_SWITCH
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
#define IFACE_(msgid)
@ SOCK_OUT
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_CLOSURE
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
@ SOCK_MENU
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
#define UI_ITEM_NONE
BMesh const char void * data
static const CPPType & get()
void move_construct(void *src, void *dst) const
static std::shared_ptr< FieldOperation > from(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:242
static SocketValueVariant & ConstructIn(void *ptr, T &&value)
void execute_impl(lf::Params &params, const lf::Context &) const override
void execute_field(Field< bool > condition, lf::Params &params) const
void execute_single(const bool condition, lf::Params &params) const
nullptr float
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
#define T
bool can_contain_reference(eNodeSocketDatatype socket_type)
bool can_contain_referenced_data(eNodeSocketDatatype socket_type)
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
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
QuaternionBase< float > Quaternion
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_init(bNodeTree *, bNode *node)
static void node_declare(NodeDeclarationBuilder &b)
static void node_rna(StructRNA *srna)
static const bNodeSocket * node_internally_linked_input(const bNodeTree &, const bNode &node, const bNodeSocket &)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
std::unique_ptr< LazyFunction > get_switch_node_lazy_function(const bNode &node)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
bool socket_type_always_single(const eNodeSocketDatatype socket_type)
const EnumPropertyItem * enum_items_filter(const EnumPropertyItem *original_item_array, FunctionRef< bool(const EnumPropertyItem &item)> fn)
MatBase< float, 4, 4 > float4x4
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)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
const EnumPropertyItem rna_enum_node_socket_data_type_items[]
StructRNA * srna
uint8_t input_type
char name[64]
int16_t type_legacy
void * storage
Defines a socket type.
Definition BKE_node.hh:158
const blender::CPPType * base_cpp_type
Definition BKE_node.hh:205
Defines a node type.
Definition BKE_node.hh:238
NodeInternallyLinkedInputFunction internally_linked_input
Definition BKE_node.hh:384
std::string ui_description
Definition BKE_node.hh:244
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
NodeDeclareFunction declare
Definition BKE_node.hh:362
bool ignore_inferred_input_socket_visibility
Definition BKE_node.hh:422
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)
PointerRNA * ptr
Definition wm_files.cc:4238