Blender V5.0
node_fn_bit_math.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Foundation
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_string.h"
6
7#include "RNA_enum_types.hh"
8
10#include "UI_resources.hh"
11
12#include "NOD_rna_define.hh"
14
15#include "node_function_util.hh"
16
17static_assert(-1 == ~0, "Two's complement must be used for bitwise operations.");
18
20
21enum BitMathOperation : int16_t {
22 And = 0,
23 Or = 1,
24 Xor = 2,
25 Not = 3,
26 Shift = 4,
27 Rotate = 5,
28};
29
30const std::array<EnumPropertyItem, 7> bit_math_operation_items = {{
32 "AND",
33 0,
34 "And",
35 "Returns a value where the bits of A and B are both set"},
37 "OR",
38 0,
39 "Or",
40 "Returns a value where the bits of either A or B are set"},
42 "XOR",
43 0,
44 "Exclusive Or",
45 "Returns a value where only one bit from A and B is set"},
47 "NOT",
48 0,
49 "Not",
50 "Returns the opposite bit value of A, in decimal it is equivalent of A = -A - 1"},
52 "SHIFT",
53 0,
54 "Shift",
55 "Shifts the bit values of A by the specified Shift amount. Positive values shift left, "
56 "negative values shift right."},
58 "ROTATE",
59 0,
60 "Rotate",
61 "Rotates the bit values of A by the specified Shift amount. Positive values rotate left, "
62 "negative values rotate right."},
63 {0, nullptr, 0, nullptr, nullptr},
64}};
65
66constexpr static int32_t max_shift = sizeof(int32_t) * CHAR_BIT - 1;
67constexpr static int32_t min_shift = -max_shift;
68
70{
71 b.is_function_node();
72 b.add_input<decl::Int>("A");
73 auto &b_socket = b.add_input<decl::Int>("B");
74 auto &shift = b.add_input<decl::Int>("Shift").min(min_shift).max(max_shift);
75 b.add_output<decl::Int>("Value");
76
77 if (const bNode *node = b.node_or_null()) {
78 const BitMathOperation operation = BitMathOperation(node->custom1);
79 b_socket.available(!ELEM(
81 shift.available(ELEM(operation, BitMathOperation::Shift, BitMathOperation::Rotate));
82 }
83};
84
85static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
86{
87 layout->prop(ptr, "operation", UI_ITEM_NONE, "", ICON_NONE);
88}
89
91 public:
92 std::string socket_name;
95 {
96 bNode &node = params.add_node("FunctionNodeBitMath");
97 node.custom1 = int16_t(operation);
98 params.update_and_connect_available_socket(node, socket_name);
99 }
100};
101
103{
104 if (!params.node_tree().typeinfo->validate_link(eNodeSocketDatatype(params.other_socket().type),
105 SOCK_INT))
106 {
107 return;
108 }
109
110 const bool is_integer = params.other_socket().type == SOCK_INT;
111 const int weight = is_integer ? 0 : -1;
112
113 for (const auto &item : bit_math_operation_items) {
114 if (item.name != nullptr && item.identifier[0] != '\0') {
115 params.add_item(
116 IFACE_(item.name), SocketSearchOp{"A", BitMathOperation(item.value)}, weight);
117 }
118 }
119}
120
121static void node_label(const bNodeTree * /*ntree*/,
122 const bNode *node,
123 char *label,
124 int label_maxncpy)
125{
126 char name[64] = {0};
127 const char *operation_name = IFACE_("Unknown");
128 /* NOTE: This assumes that the matching RNA enum property also uses the default i18n context, and
129 * needs to be kept manually in sync. */
131 bit_math_operation_items.data(), node->custom1, BLT_I18NCONTEXT_DEFAULT, &operation_name);
132 SNPRINTF(name, IFACE_("Bitwise %s"), operation_name);
133 BLI_strncpy(label, name, label_maxncpy);
134}
135
136static const mf::MultiFunction *get_multi_function(const bNode &bnode)
137{
138 const BitMathOperation operation = BitMathOperation(bnode.custom1);
139 static auto exec_preset = mf::build::exec_presets::AllSpanOrSingle();
140 static auto and_fn = mf::build::SI2_SO<int, int, int>(
141 "And", [](int a, int b) { return a & b; }, exec_preset);
142 static auto or_fn = mf::build::SI2_SO<int, int, int>(
143 "Or", [](int a, int b) { return a | b; }, exec_preset);
144 static auto xor_fn = mf::build::SI2_SO<int, int, int>(
145 "Xor", [](int a, int b) { return a ^ b; }, exec_preset);
146 static auto not_fn = mf::build::SI1_SO<int, int>("Not", [](int a) { return ~a; }, exec_preset);
147 static auto shift_fn = mf::build::SI2_SO<int, int, int>(
148 "Shift",
149 [](int a, int b) {
150 const uint32_t value = a;
151 const int shift = math::clamp(b, -32, 32);
152 const uint64_t wide_value = uint64_t(value) << 16;
153 const uint64_t wide_result = shift > 0 ? wide_value << shift : wide_value >> -shift;
154 return uint32_t(wide_result >> 16);
155 },
156 exec_preset);
157 static auto rotate_fn = mf::build::SI2_SO<int, int, int>(
158 "Rotate",
159 [](int a, int b) {
160 const uint32_t value = a;
161 const int shift = math::mod_periodic(b, 32);
162 const uint64_t wide_value = uint64_t(value) | (uint64_t(value) << 32);
163 const uint64_t double_result = (wide_value << shift);
164 return uint32_t((double_result | (double_result >> 32)) & ((uint64_t(1) << 33) - 1));
165 },
166 exec_preset);
167
168 switch (operation) {
170 return &and_fn;
172 return &or_fn;
174 return &xor_fn;
176 return &not_fn;
178 return &shift_fn;
180 return &rotate_fn;
181 }
183 return nullptr;
184}
185
187{
188 const mf::MultiFunction *fn = get_multi_function(builder.node());
189 builder.set_matching_fn(fn);
190}
191
192static void node_rna(StructRNA *srna)
193{
194 PropertyRNA *prop = RNA_def_node_enum(srna,
195 "operation",
196 "Operation",
197 "",
202}
203
204static void node_register()
205{
206 static blender::bke::bNodeType ntype;
207
208 fn_node_type_base(&ntype, "FunctionNodeBitMath");
209 ntype.ui_name = "Bit Math";
211 ntype.declare = node_declare;
212 ntype.labelfunc = node_label;
216 ntype.ui_description = "Perform bitwise operations on 32-bit integers";
217
219 node_rna(ntype.rna_ext.srna);
220}
222
223} // namespace blender::nodes::node_fn_bit_math_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:453
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define ELEM(...)
#define BLT_I18NCONTEXT_DEFAULT
#define IFACE_(msgid)
eNodeSocketDatatype
@ SOCK_INT
#define NOD_REGISTER_NODE(REGISTER_FUNC)
void rna_Node_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
#define NOD_inline_enum_accessors(member)
#define UI_ITEM_NONE
unsigned long long int uint64_t
void set_matching_fn(const mf::MultiFunction *fn)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
T clamp(const T &a, const T &min, const T &max)
T mod_periodic(const T &a, const T &b)
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
const std::array< EnumPropertyItem, 7 > bit_math_operation_items
static void node_declare(NodeDeclarationBuilder &b)
static const mf::MultiFunction * get_multi_function(const bNode &bnode)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_label(const bNodeTree *, const bNode *node, char *label, int label_maxncpy)
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)
void fn_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
const char * name
bool RNA_enum_name_gettexted(const EnumPropertyItem *item, int value, const char *translation_context, const char **r_name)
void RNA_def_property_update_runtime(PropertyRNA *prop, RNAPropertyUpdateFunc func)
#define min(a, b)
Definition sort.cc:36
StructRNA * srna
int16_t custom1
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:270
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:351
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
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