Blender V4.5
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
7#include "UI_interface.hh"
8#include "UI_resources.hh"
9
10#include "NOD_rna_define.hh"
11#include "NOD_socket.hh"
13
14#include "RNA_enum_types.hh"
15
17
19
21
23{
24 auto &switch_decl = b.add_input<decl::Bool>("Switch");
25 const bNode *node = b.node_or_null();
26 if (!node) {
27 return;
28 }
29 const NodeSwitch &storage = node_storage(*node);
30 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(storage.input_type);
31
32 auto &false_decl = b.add_input(socket_type, "False");
33 auto &true_decl = b.add_input(socket_type, "True");
34 auto &output_decl = b.add_output(socket_type, "Output");
35
36 if (socket_type_supports_fields(socket_type)) {
37 switch_decl.supports_field();
38 false_decl.supports_field();
39 true_decl.supports_field();
40 output_decl.dependent_field().reference_pass_all();
41 }
42 if (socket_type == SOCK_GEOMETRY) {
43 output_decl.propagate_all();
44 }
45}
46
47static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
48{
49 layout->prop(ptr, "input_type", UI_ITEM_NONE, "", ICON_NONE);
50}
51
52static void node_init(bNodeTree * /*tree*/, bNode *node)
53{
55 data->input_type = SOCK_GEOMETRY;
56 node->storage = data;
57}
58
60{
61 if (params.in_out() == SOCK_OUT) {
62 params.add_item(IFACE_("Output"), [](LinkSearchOpParams &params) {
63 bNode &node = params.add_node("GeometryNodeSwitch");
64 node_storage(node).input_type = params.socket.type;
65 params.update_and_connect_available_socket(node, "Output");
66 });
67 }
68 else {
69 /* Make sure the switch input comes first in the search for boolean sockets. */
70 int true_false_weights = 0;
71 if (params.other_socket().type == SOCK_BOOLEAN) {
72 params.add_item(IFACE_("Switch"), [](LinkSearchOpParams &params) {
73 bNode &node = params.add_node("GeometryNodeSwitch");
74 params.update_and_connect_available_socket(node, "Switch");
75 });
76 true_false_weights--;
77 }
78
79 params.add_item(
80 IFACE_("False"),
82 bNode &node = params.add_node("GeometryNodeSwitch");
83 node_storage(node).input_type = params.socket.type;
84 params.update_and_connect_available_socket(node, "False");
85 },
86 true_false_weights);
87 params.add_item(
88 IFACE_("True"),
90 bNode &node = params.add_node("GeometryNodeSwitch");
91 node_storage(node).input_type = params.socket.type;
92 params.update_and_connect_available_socket(node, "True");
93 },
94 true_false_weights);
95 }
96}
97
99 private:
100 bool can_be_field_ = false;
101 const CPPType *base_type_;
102
103 public:
105 {
106 const NodeSwitch &storage = node_storage(node);
107 const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.input_type);
108 can_be_field_ = socket_type_supports_fields(data_type);
109
110 const bke::bNodeSocketType *socket_type = nullptr;
111 for (const bNodeSocket *socket : node.output_sockets()) {
112 if (socket->type == data_type) {
113 socket_type = socket->typeinfo;
114 break;
115 }
116 }
117 BLI_assert(socket_type != nullptr);
118 const CPPType &cpp_type = *socket_type->geometry_nodes_cpp_type;
119 base_type_ = socket_type->base_cpp_type;
120
121 debug_name_ = node.name;
122 inputs_.append_as("Condition", CPPType::get<SocketValueVariant>());
123 inputs_.append_as("False", cpp_type, lf::ValueUsage::Maybe);
124 inputs_.append_as("True", cpp_type, lf::ValueUsage::Maybe);
125 outputs_.append_as("Value", cpp_type);
126 }
127
128 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
129 {
130 SocketValueVariant condition_variant = params.get_input<SocketValueVariant>(0);
131 if (condition_variant.is_context_dependent_field() && can_be_field_) {
132 this->execute_field(condition_variant.get<Field<bool>>(), params);
133 }
134 else {
135 this->execute_single(condition_variant.get<bool>(), params);
136 }
137 }
138
139 static constexpr int false_input_index = 1;
140 static constexpr int true_input_index = 2;
141
142 void execute_single(const bool condition, lf::Params &params) const
143 {
144 const int input_to_forward = condition ? true_input_index : false_input_index;
145 const int input_to_ignore = condition ? false_input_index : true_input_index;
146
147 params.set_input_unused(input_to_ignore);
148 void *value_to_forward = params.try_get_input_data_ptr_or_request(input_to_forward);
149 if (value_to_forward == nullptr) {
150 /* Try again when the value is available. */
151 return;
152 }
153
154 const CPPType &type = *outputs_[0].type;
155 void *output_ptr = params.get_output_data_ptr(0);
156 type.move_construct(value_to_forward, output_ptr);
157 params.output_set(0);
158 }
159
161 {
162 /* When the condition is a non-constant field, we need both inputs. */
163 auto *false_value_variant = params.try_get_input_data_ptr_or_request<SocketValueVariant>(
165 auto *true_value_variant = params.try_get_input_data_ptr_or_request<SocketValueVariant>(
167 if (ELEM(nullptr, false_value_variant, true_value_variant)) {
168 /* Try again when inputs are available. */
169 return;
170 }
171
172 const MultiFunction &switch_multi_function = this->get_switch_multi_function();
173
174 GField false_field = false_value_variant->extract<GField>();
175 GField true_field = true_value_variant->extract<GField>();
176
177 GField output_field{FieldOperation::Create(
178 switch_multi_function,
179 {std::move(condition), std::move(false_field), std::move(true_field)})};
180
181 void *output_ptr = params.get_output_data_ptr(0);
182 new (output_ptr) SocketValueVariant(std::move(output_field));
183 params.output_set(0);
184 }
185
186 const MultiFunction &get_switch_multi_function() const
187 {
188 const MultiFunction *switch_multi_function = nullptr;
189 base_type_->to_static_type_tag<float,
190 int,
191 bool,
192 float3,
194 std::string,
196 float4x4>([&](auto type_tag) {
197 using T = typename decltype(type_tag)::type;
198 if constexpr (std::is_void_v<T>) {
200 }
201 else {
202 static auto switch_fn = mf::build::SI3_SO<bool, T, T, T>(
203 "Switch", [](const bool condition, const T &false_value, const T &true_value) {
204 return condition ? true_value : false_value;
205 });
206 switch_multi_function = &switch_fn;
207 }
208 });
209 BLI_assert(switch_multi_function != nullptr);
210 return *switch_multi_function;
211 }
212};
213
215 const bNode &node,
216 const bNodeSocket & /*output_socket*/)
217{
218 /* Default to the False input. */
219 return &node.input_socket(1);
220}
221
222static void node_rna(StructRNA *srna)
223{
225 srna,
226 "input_type",
227 "Input Type",
228 "",
230 NOD_storage_enum_accessors(input_type),
232 [](bContext * /*C*/, PointerRNA * /*ptr*/, PropertyRNA * /*prop*/, bool *r_free) {
233 *r_free = true;
235 [](const EnumPropertyItem &item) -> bool {
236 if (!U.experimental.use_bundle_and_closure_nodes) {
237 if (ELEM(item.value, SOCK_BUNDLE, SOCK_CLOSURE)) {
238 return false;
239 }
240 }
241 return ELEM(item.value,
243 SOCK_INT,
249 SOCK_RGBA,
255 SOCK_MENU,
258 });
259 });
260}
261
262static void register_node()
263{
264 static blender::bke::bNodeType ntype;
265
266 geo_node_type_base(&ntype, "GeometryNodeSwitch", GEO_NODE_SWITCH);
267 ntype.ui_name = "Switch";
268 ntype.ui_description = "Switch between two inputs";
269 ntype.enum_name_legacy = "SWITCH";
271 ntype.declare = node_declare;
272 ntype.initfunc = node_init;
280
281 node_rna(ntype.rna_ext.srna);
282}
284
285} // namespace blender::nodes::node_geo_switch_cc
286
287namespace blender::nodes {
288
289std::unique_ptr<LazyFunction> get_switch_node_lazy_function(const bNode &node)
290{
291 using namespace node_geo_switch_cc;
293 return std::make_unique<LazyFunctionForSwitchNode>(node);
294}
295
296} // namespace blender::nodes
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:439
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1215
#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
#define U
BMesh const char void * data
static const CPPType & get()
void move_construct(void *src, void *dst) const
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:242
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
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
#define T
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
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:5603
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)
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
Definition BLI_color.hh:342
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
Definition RNA_types.hh:909
uint8_t input_type
char name[64]
int16_t type_legacy
void * storage
Defines a socket type.
Definition BKE_node.hh:152
const blender::CPPType * geometry_nodes_cpp_type
Definition BKE_node.hh:203
const blender::CPPType * base_cpp_type
Definition BKE_node.hh:199
Defines a node type.
Definition BKE_node.hh:226
NodeInternallyLinkedInputFunction internally_linked_input
Definition BKE_node.hh:377
std::string ui_description
Definition BKE_node.hh:232
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
const char * enum_name_legacy
Definition BKE_node.hh:235
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:247
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:371
NodeDeclareFunction declare
Definition BKE_node.hh:355
bool ignore_inferred_input_socket_visibility
Definition BKE_node.hh:415
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:4227