Blender V4.5
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
9#include "UI_interface.hh"
10
11#include "NOD_rna_define.hh"
13
14#include "node_function_util.hh"
15
16static_assert(-1 == ~0, "Two's complement must be used for bitwise operations.");
17
19
20enum BitMathOperation : int16_t {
21 And = 0,
22 Or = 1,
23 Xor = 2,
24 Not = 3,
25 Shift = 4,
26 Rotate = 5,
27};
28
29const std::array<EnumPropertyItem, 7> bit_math_operation_items = {{
31 "AND",
32 0,
33 "And",
34 "Returns a value where the bits of A and B are both set"},
36 "OR",
37 0,
38 "Or",
39 "Returns a value where the bits of either A or B are set"},
41 "XOR",
42 0,
43 "Exclusive Or",
44 "Returns a value where only one bit from A and B is set"},
46 "NOT",
47 0,
48 "Not",
49 "Returns the opposite bit value of A, in decimal it is equivalent of A = -A - 1"},
51 "SHIFT",
52 0,
53 "Shift",
54 "Shifts the bit values of A by the specified Shift amount. Positive values shift left, "
55 "negative values shift right."},
57 "ROTATE",
58 0,
59 "Rotate",
60 "Rotates the bit values of A by the specified Shift amount. Positive values rotate left, "
61 "negative values rotate right."},
62 {0, nullptr, 0, nullptr, nullptr},
63}};
64
65constexpr static int32_t max_shift = sizeof(int32_t) * CHAR_BIT - 1;
66constexpr static int32_t min_shift = -max_shift;
67
69{
70 b.is_function_node();
71 b.add_input<decl::Int>("A");
72 auto &b_socket = b.add_input<decl::Int>("B");
73 auto &shift = b.add_input<decl::Int>("Shift").min(min_shift).max(max_shift);
74 b.add_output<decl::Int>("Value");
75
76 if (const bNode *node = b.node_or_null()) {
77 const BitMathOperation operation = BitMathOperation(node->custom1);
78 b_socket.available(!ELEM(
80 shift.available(ELEM(operation, BitMathOperation::Shift, BitMathOperation::Rotate));
81 }
82};
83
84static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
85{
86 layout->prop(ptr, "operation", UI_ITEM_NONE, "", ICON_NONE);
87}
88
90 public:
91 std::string socket_name;
94 {
95 bNode &node = params.add_node("FunctionNodeBitMath");
96 node.custom1 = int16_t(operation);
97 params.update_and_connect_available_socket(node, socket_name);
98 }
99};
100
102{
103 if (!params.node_tree().typeinfo->validate_link(eNodeSocketDatatype(params.other_socket().type),
104 SOCK_INT))
105 {
106 return;
107 }
108
109 const bool is_integer = params.other_socket().type == SOCK_INT;
110 const int weight = is_integer ? 0 : -1;
111
112 for (const auto &item : bit_math_operation_items) {
113 if (item.name != nullptr && item.identifier[0] != '\0') {
114 params.add_item(
115 IFACE_(item.name), SocketSearchOp{"A", BitMathOperation(item.value)}, weight);
116 }
117 }
118}
119
120static void node_label(const bNodeTree * /*ntree*/, const bNode *node, char *label, int maxlen)
121{
122 char name[64] = {0};
123 const char *operation_name = IFACE_("Unknown");
124 /* NOTE: This assumes that the matching RNA enum property also uses the default i18n context, and
125 * needs to be kept manually in sync. */
127 bit_math_operation_items.data(), node->custom1, BLT_I18NCONTEXT_DEFAULT, &operation_name);
128 SNPRINTF(name, IFACE_("Bitwise %s"), operation_name);
129 BLI_strncpy(label, name, maxlen);
130}
131
132static const mf::MultiFunction *get_multi_function(const bNode &bnode)
133{
134 const BitMathOperation operation = BitMathOperation(bnode.custom1);
135 static auto exec_preset = mf::build::exec_presets::AllSpanOrSingle();
136 static auto and_fn = mf::build::SI2_SO<int, int, int>(
137 "And", [](int a, int b) { return a & b; }, exec_preset);
138 static auto or_fn = mf::build::SI2_SO<int, int, int>(
139 "Or", [](int a, int b) { return a | b; }, exec_preset);
140 static auto xor_fn = mf::build::SI2_SO<int, int, int>(
141 "Xor", [](int a, int b) { return a ^ b; }, exec_preset);
142 static auto not_fn = mf::build::SI1_SO<int, int>(
143 "Not", [](int a) { return ~a; }, exec_preset);
144 static auto shift_fn = mf::build::SI2_SO<int, int, int>(
145 "Shift",
146 [](int a, int b) {
147 const uint32_t value = a;
148 const int shift = math::clamp(b, -32, 32);
149 const uint64_t wide_value = uint64_t(value) << 16;
150 const uint64_t wide_result = shift > 0 ? wide_value << shift : wide_value >> -shift;
151 return uint32_t(wide_result >> 16);
152 },
153 exec_preset);
154 static auto rotate_fn = mf::build::SI2_SO<int, int, int>(
155 "Rotate",
156 [](int a, int b) {
157 const uint32_t value = a;
158 const int shift = math::mod_periodic(b, 32);
159 const uint64_t wide_value = uint64_t(value) | (uint64_t(value) << 32);
160 const uint64_t double_result = (wide_value << shift);
161 return uint32_t((double_result | (double_result >> 32)) & ((uint64_t(1) << 33) - 1));
162 },
163 exec_preset);
164
165 switch (operation) {
167 return &and_fn;
169 return &or_fn;
171 return &xor_fn;
173 return &not_fn;
175 return &shift_fn;
177 return &rotate_fn;
178 }
180 return nullptr;
181}
182
184{
185 const mf::MultiFunction *fn = get_multi_function(builder.node());
186 builder.set_matching_fn(fn);
187}
188
189static void node_rna(StructRNA *srna)
190{
191 PropertyRNA *prop = RNA_def_node_enum(srna,
192 "operation",
193 "Operation",
194 "",
199}
200
201static void node_register()
202{
203 static blender::bke::bNodeType ntype;
204
205 fn_node_type_base(&ntype, "FunctionNodeBitMath");
206 ntype.ui_name = "Bit Math";
208 ntype.declare = node_declare;
209 ntype.labelfunc = node_label;
213 ntype.ui_description = "Perform bitwise operations on 32-bit integers";
214
216 node_rna(ntype.rna_ext.srna);
217}
219
220} // namespace blender::nodes::node_fn_bit_math_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:439
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
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:2748
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 void node_label(const bNodeTree *, const bNode *node, char *label, int maxlen)
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_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)
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
Definition RNA_types.hh:909
int16_t custom1
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:258
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:344
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
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