Blender V4.3
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{
22 auto &switch_decl = b.add_input<decl::Bool>("Switch");
23 const bNode *node = b.node_or_null();
24 if (!node) {
25 return;
26 }
27 const NodeSwitch &storage = node_storage(*node);
28 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(storage.input_type);
29
30 auto &false_decl = b.add_input(socket_type, "False");
31 auto &true_decl = b.add_input(socket_type, "True");
32 auto &output_decl = b.add_output(socket_type, "Output");
33
34 if (socket_type_supports_fields(socket_type)) {
35 switch_decl.supports_field();
36 false_decl.supports_field();
37 true_decl.supports_field();
38 output_decl.dependent_field().reference_pass_all();
39 }
40 if (socket_type == SOCK_GEOMETRY) {
41 output_decl.propagate_all();
42 }
43}
44
45static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
46{
47 uiItemR(layout, ptr, "input_type", UI_ITEM_NONE, "", ICON_NONE);
48}
49
50static void node_init(bNodeTree * /*tree*/, bNode *node)
51{
52 NodeSwitch *data = MEM_cnew<NodeSwitch>(__func__);
53 data->input_type = SOCK_GEOMETRY;
54 node->storage = data;
55}
56
58{
59 if (params.in_out() == SOCK_OUT) {
60 params.add_item(IFACE_("Output"), [](LinkSearchOpParams &params) {
61 bNode &node = params.add_node("GeometryNodeSwitch");
62 node_storage(node).input_type = params.socket.type;
63 params.update_and_connect_available_socket(node, "Output");
64 });
65 }
66 else {
67 /* Make sure the switch input comes first in the search for boolean sockets. */
68 int true_false_weights = 0;
69 if (params.other_socket().type == SOCK_BOOLEAN) {
70 params.add_item(IFACE_("Switch"), [](LinkSearchOpParams &params) {
71 bNode &node = params.add_node("GeometryNodeSwitch");
72 params.update_and_connect_available_socket(node, "Switch");
73 });
74 true_false_weights--;
75 }
76
77 params.add_item(
78 IFACE_("False"),
80 bNode &node = params.add_node("GeometryNodeSwitch");
81 node_storage(node).input_type = params.socket.type;
82 params.update_and_connect_available_socket(node, "False");
83 },
84 true_false_weights);
85 params.add_item(
86 IFACE_("True"),
88 bNode &node = params.add_node("GeometryNodeSwitch");
89 node_storage(node).input_type = params.socket.type;
90 params.update_and_connect_available_socket(node, "True");
91 },
92 true_false_weights);
93 }
94}
95
97 private:
98 bool can_be_field_ = false;
99 const CPPType *base_type_;
100
101 public:
103 {
104 const NodeSwitch &storage = node_storage(node);
105 const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.input_type);
106 can_be_field_ = socket_type_supports_fields(data_type);
107
108 const bke::bNodeSocketType *socket_type = nullptr;
109 for (const bNodeSocket *socket : node.output_sockets()) {
110 if (socket->type == data_type) {
111 socket_type = socket->typeinfo;
112 break;
113 }
114 }
115 BLI_assert(socket_type != nullptr);
116 const CPPType &cpp_type = *socket_type->geometry_nodes_cpp_type;
117 base_type_ = socket_type->base_cpp_type;
118
119 debug_name_ = node.name;
120 inputs_.append_as("Condition", CPPType::get<SocketValueVariant>());
121 inputs_.append_as("False", cpp_type, lf::ValueUsage::Maybe);
122 inputs_.append_as("True", cpp_type, lf::ValueUsage::Maybe);
123 outputs_.append_as("Value", cpp_type);
124 }
125
126 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
127 {
128 SocketValueVariant condition_variant = params.get_input<SocketValueVariant>(0);
129 if (condition_variant.is_context_dependent_field() && can_be_field_) {
130 this->execute_field(condition_variant.get<Field<bool>>(), params);
131 }
132 else {
133 this->execute_single(condition_variant.get<bool>(), params);
134 }
135 }
136
137 static constexpr int false_input_index = 1;
138 static constexpr int true_input_index = 2;
139
140 void execute_single(const bool condition, lf::Params &params) const
141 {
142 const int input_to_forward = condition ? true_input_index : false_input_index;
143 const int input_to_ignore = condition ? false_input_index : true_input_index;
144
145 params.set_input_unused(input_to_ignore);
146 void *value_to_forward = params.try_get_input_data_ptr_or_request(input_to_forward);
147 if (value_to_forward == nullptr) {
148 /* Try again when the value is available. */
149 return;
150 }
151
152 const CPPType &type = *outputs_[0].type;
153 void *output_ptr = params.get_output_data_ptr(0);
154 type.move_construct(value_to_forward, output_ptr);
155 params.output_set(0);
156 }
157
159 {
160 /* When the condition is a non-constant field, we need both inputs. */
161 auto *false_value_variant = params.try_get_input_data_ptr_or_request<SocketValueVariant>(
163 auto *true_value_variant = params.try_get_input_data_ptr_or_request<SocketValueVariant>(
165 if (ELEM(nullptr, false_value_variant, true_value_variant)) {
166 /* Try again when inputs are available. */
167 return;
168 }
169
170 const MultiFunction &switch_multi_function = this->get_switch_multi_function();
171
172 GField false_field = false_value_variant->extract<GField>();
173 GField true_field = true_value_variant->extract<GField>();
174
175 GField output_field{FieldOperation::Create(
176 switch_multi_function,
177 {std::move(condition), std::move(false_field), std::move(true_field)})};
178
179 void *output_ptr = params.get_output_data_ptr(0);
180 new (output_ptr) SocketValueVariant(std::move(output_field));
181 params.output_set(0);
182 }
183
185 {
186 const MultiFunction *switch_multi_function = nullptr;
187 base_type_->to_static_type_tag<float,
188 int,
189 bool,
190 float3,
192 std::string,
194 float4x4>([&](auto type_tag) {
195 using T = typename decltype(type_tag)::type;
196 if constexpr (std::is_void_v<T>) {
198 }
199 else {
200 static auto switch_fn = mf::build::SI3_SO<bool, T, T, T>(
201 "Switch", [](const bool condition, const T &false_value, const T &true_value) {
202 return condition ? true_value : false_value;
203 });
204 switch_multi_function = &switch_fn;
205 }
206 });
207 BLI_assert(switch_multi_function != nullptr);
208 return *switch_multi_function;
209 }
210};
211
212static void node_rna(StructRNA *srna)
213{
215 srna,
216 "input_type",
217 "Input Type",
218 "",
220 NOD_storage_enum_accessors(input_type),
222 [](bContext * /*C*/, PointerRNA * /*ptr*/, PropertyRNA * /*prop*/, bool *r_free) {
223 *r_free = true;
225 [](const EnumPropertyItem &item) -> bool {
226 return ELEM(item.value,
228 SOCK_INT,
234 SOCK_RGBA,
240 SOCK_MENU);
241 });
242 });
243}
244
245static void register_node()
246{
247 static blender::bke::bNodeType ntype;
248
249 geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER);
250 ntype.declare = node_declare;
251 ntype.initfunc = node_init;
257
258 node_rna(ntype.rna_ext.srna);
259}
261
262} // namespace blender::nodes::node_geo_switch_cc
263
264namespace blender::nodes {
265
266std::unique_ptr<LazyFunction> get_switch_node_lazy_function(const bNode &node)
267{
268 using namespace node_geo_switch_cc;
269 BLI_assert(node.type == GEO_NODE_SWITCH);
270 return std::make_unique<LazyFunctionForSwitchNode>(node);
271}
272
273} // namespace blender::nodes
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:410
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ELEM(...)
#define IFACE_(msgid)
@ SOCK_OUT
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ 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
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
StringRefNull name() const
static const CPPType & get()
void to_static_type_tag(const Fn &fn) const
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:244
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
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
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)
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)
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:46
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:58
const EnumPropertyItem rna_enum_node_socket_data_type_items[]
StructRNA * srna
Definition RNA_types.hh:780
uint8_t input_type
Defines a socket type.
Definition BKE_node.hh:151
const blender::CPPType * geometry_nodes_cpp_type
Definition BKE_node.hh:195
const blender::CPPType * base_cpp_type
Definition BKE_node.hh:191
Defines a node type.
Definition BKE_node.hh:218
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:363
NodeDeclareFunction declare
Definition BKE_node.hh:347
PointerRNA * ptr
Definition wm_files.cc:4126