Blender V5.0
node_fn_integer_math.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Foundation
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <numeric>
6
7#include "BLI_math_base.h"
8#include "BLI_string.h"
9
10#include "RNA_enum_types.hh"
11
13#include "UI_resources.hh"
14
16#include "NOD_rna_define.hh"
19
20#include "node_function_util.hh"
21
23
25{
26 b.is_function_node();
27 b.add_input<decl::Int>("Value");
28 b.add_input<decl::Int>("Value", "Value_001");
29 b.add_input<decl::Int>("Value", "Value_002");
30 b.add_output<decl::Int>("Value");
31};
32
33static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
34{
35 layout->prop(ptr, "operation", UI_ITEM_NONE, "", ICON_NONE);
36}
37
38static void node_update(bNodeTree *ntree, bNode *node)
39{
40 const bool one_input_ops = ELEM(
42 const bool three_input_ops = ELEM(node->custom1, NODE_INTEGER_MATH_MULTIPLY_ADD);
43
44 bNodeSocket *sockA = static_cast<bNodeSocket *>(node->inputs.first);
45 bNodeSocket *sockB = sockA->next;
46 bNodeSocket *sockC = sockB->next;
47
48 bke::node_set_socket_availability(*ntree, *sockB, !one_input_ops);
49 bke::node_set_socket_availability(*ntree, *sockC, three_input_ops);
50
54 switch (node->custom1) {
56 node_sock_label(sockA, N_("Value"));
57 node_sock_label(sockB, N_("Multiplier"));
58 node_sock_label(sockC, N_("Addend"));
59 break;
61 node_sock_label(sockA, N_("Base"));
62 node_sock_label(sockB, N_("Exponent"));
63 break;
64 }
65}
66
68 public:
69 std::string socket_name;
72 {
73 bNode &node = params.add_node("FunctionNodeIntegerMath");
75 params.update_and_connect_available_socket(node, socket_name);
76 }
77};
78
80{
81 if (!params.node_tree().typeinfo->validate_link(eNodeSocketDatatype(params.other_socket().type),
82 SOCK_INT))
83 {
84 return;
85 }
86
87 const bool is_integer = params.other_socket().type == SOCK_INT;
88 const int weight = is_integer ? 0 : -1;
89
90 /* Add socket A operations. */
92 item->identifier != nullptr;
93 item++)
94 {
95 if (item->name != nullptr && item->identifier[0] != '\0') {
96 params.add_item(CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, item->name),
97 SocketSearchOp{"Value", NodeIntegerMathOperation(item->value)},
98 weight);
99 }
100 }
101}
102
103static void node_label(const bNodeTree * /*ntree*/,
104 const bNode *node,
105 char *label,
106 int label_maxncpy)
107{
108 const char *name;
110 if (!enum_label) {
112 }
114}
115
116/* Derived from `divide_round_i` but fixed to be safe and handle negative inputs. */
117static int safe_divide_round_i(const int a, const int b)
118{
119 const int c = math::abs(b);
120 return (a >= 0) ? math::safe_divide((2 * a + c), (2 * c)) * math::sign(b) :
121 -math::safe_divide((2 * -a + c), (2 * c)) * math::sign(b);
122}
123
124static const mf::MultiFunction *get_multi_function(const bNode &bnode)
125{
127 static auto exec_preset = mf::build::exec_presets::AllSpanOrSingle();
128 static auto add_fn = mf::build::SI2_SO<int, int, int>(
129 "Add", [](int a, int b) { return a + b; }, exec_preset);
130 static auto sub_fn = mf::build::SI2_SO<int, int, int>(
131 "Subtract", [](int a, int b) { return a - b; }, exec_preset);
132 static auto multiply_fn = mf::build::SI2_SO<int, int, int>(
133 "Multiply", [](int a, int b) { return a * b; }, exec_preset);
134 static auto divide_fn = mf::build::SI2_SO<int, int, int>(
135 "Divide", [](int a, int b) { return math::safe_divide(a, b); }, exec_preset);
136 static auto divide_floor_fn = mf::build::SI2_SO<int, int, int>(
137 "Divide Floor",
138 [](int a, int b) { return (b != 0) ? divide_floor_i(a, b) : 0; },
139 exec_preset);
140 static auto divide_ceil_fn = mf::build::SI2_SO<int, int, int>(
141 "Divide Ceil",
142 [](int a, int b) { return (b != 0) ? -divide_floor_i(a, -b) : 0; },
143 exec_preset);
144 static auto divide_round_fn = mf::build::SI2_SO<int, int, int>(
145 "Divide Round", [](int a, int b) { return safe_divide_round_i(a, b); }, exec_preset);
146 static auto pow_fn = mf::build::SI2_SO<int, int, int>(
147 "Power", [](int a, int b) { return math::pow(a, b); }, exec_preset);
148 static auto madd_fn = mf::build::SI3_SO<int, int, int, int>(
149 "Multiply Add", [](int a, int b, int c) { return a * b + c; }, exec_preset);
150 static auto floored_mod_fn = mf::build::SI2_SO<int, int, int>(
151 "Floored Modulo",
152 [](int a, int b) { return b != 0 ? math::mod_periodic(a, b) : 0; },
153 exec_preset);
154 static auto mod_fn = mf::build::SI2_SO<int, int, int>(
155 "Modulo", [](int a, int b) { return b != 0 ? a % b : 0; }, exec_preset);
156 static auto abs_fn = mf::build::SI1_SO<int, int>(
157 "Absolute", [](int a) { return math::abs(a); }, exec_preset);
158 static auto sign_fn = mf::build::SI1_SO<int, int>(
159 "Sign", [](int a) { return math::sign(a); }, exec_preset);
160 static auto min_fn = mf::build::SI2_SO<int, int, int>(
161 "Minimum", [](int a, int b) { return math::min(a, b); }, exec_preset);
162 static auto max_fn = mf::build::SI2_SO<int, int, int>(
163 "Maximum", [](int a, int b) { return math::max(a, b); }, exec_preset);
164 static auto gcd_fn = mf::build::SI2_SO<int, int, int>(
165 "GCD", [](int a, int b) { return std::gcd(a, b); }, exec_preset);
166 static auto lcm_fn = mf::build::SI2_SO<int, int, int>(
167 "LCM", [](int a, int b) { return std::lcm(a, b); }, exec_preset);
168 static auto negate_fn = mf::build::SI1_SO<int, int>(
169 "Negate", [](int a) { return -a; }, exec_preset);
170
171 switch (operation) {
173 return &add_fn;
175 return &sub_fn;
177 return &multiply_fn;
179 return &divide_fn;
181 return &divide_floor_fn;
183 return &divide_ceil_fn;
185 return &divide_round_fn;
187 return &pow_fn;
189 return &madd_fn;
191 return &floored_mod_fn;
193 return &mod_fn;
195 return &abs_fn;
197 return &sign_fn;
199 return &min_fn;
201 return &max_fn;
203 return &gcd_fn;
205 return &lcm_fn;
207 return &negate_fn;
208 }
210 return nullptr;
211}
212
214{
215 const mf::MultiFunction *fn = get_multi_function(builder.node());
216 builder.set_matching_fn(fn);
217}
218
220{
221 using namespace value_elem;
223 switch (op) {
228 IntElem output_elem = params.get_input_elem<IntElem>("Value");
229 output_elem.merge(params.get_input_elem<IntElem>("Value_001"));
230 params.set_output_elem("Value", output_elem);
231 break;
232 }
233 default:
234 break;
235 }
236}
237
239{
241 switch (op) {
246 params.set_input_elem("Value", params.get_output_elem<value_elem::IntElem>("Value"));
247 break;
248 }
249 default:
250 break;
251 }
252}
253
255{
257 const StringRef first_input_id = "Value";
258 const StringRef second_input_id = "Value_001";
259 const StringRef output_id = "Value";
260 switch (op) {
262 params.set_input(first_input_id,
263 params.get_output<int>(output_id) - params.get_input<int>(second_input_id));
264 break;
265 }
267 params.set_input(first_input_id,
268 params.get_output<int>(output_id) + params.get_input<int>(second_input_id));
269 break;
270 }
272 params.set_input(first_input_id,
273 math::safe_divide(params.get_output<int>(output_id),
274 params.get_input<int>(second_input_id)));
275 break;
276 }
278 params.set_input(first_input_id,
279 params.get_output<int>(output_id) * params.get_input<int>(second_input_id));
280 break;
281 }
282 default: {
283 break;
284 }
285 }
286}
287
288static void node_rna(StructRNA *srna)
289{
290 PropertyRNA *prop;
291
292 prop = RNA_def_node_enum(srna,
293 "operation",
294 "Operation",
295 "",
301}
302
303static void node_register()
304{
305 static blender::bke::bNodeType ntype;
306
307 fn_node_type_base(&ntype, "FunctionNodeIntegerMath", FN_NODE_INTEGER_MATH);
308 ntype.ui_name = "Integer Math";
309 ntype.ui_description = "Perform various math operations on the given integer inputs";
310 ntype.enum_name_legacy = "INTEGER_MATH";
312 ntype.declare = node_declare;
313 ntype.labelfunc = node_label;
314 ntype.updatefunc = node_update;
321
323
324 node_rna(ntype.rna_ext.srna);
325}
327
328} // namespace blender::nodes::node_fn_integer_math_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:453
#define FN_NODE_INTEGER_MATH
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define ELEM(...)
#define CTX_N_(context, msgid)
#define BLT_I18NCONTEXT_ID_NODETREE
#define CTX_IFACE_(context, msgid)
eNodeSocketDatatype
@ SOCK_INT
NodeIntegerMathOperation
@ NODE_INTEGER_MATH_SIGN
@ NODE_INTEGER_MATH_ABSOLUTE
@ NODE_INTEGER_MATH_MODULO
@ NODE_INTEGER_MATH_POWER
@ NODE_INTEGER_MATH_MINIMUM
@ NODE_INTEGER_MATH_ADD
@ NODE_INTEGER_MATH_MULTIPLY_ADD
@ NODE_INTEGER_MATH_SUBTRACT
@ NODE_INTEGER_MATH_MULTIPLY
@ NODE_INTEGER_MATH_DIVIDE_FLOOR
@ NODE_INTEGER_MATH_DIVIDE_CEIL
@ NODE_INTEGER_MATH_NEGATE
@ NODE_INTEGER_MATH_MAXIMUM
@ NODE_INTEGER_MATH_GCD
@ NODE_INTEGER_MATH_LCM
@ NODE_INTEGER_MATH_FLOORED_MODULO
@ NODE_INTEGER_MATH_DIVIDE_ROUND
@ NODE_INTEGER_MATH_DIVIDE
#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
void set_matching_fn(const mf::MultiFunction *fn)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
MINLINE int divide_floor_i(int a, int b)
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, bool is_available)
Definition node.cc:4739
T pow(const T &x, const T &power)
T safe_divide(const T &a, const T &b)
T sign(const T &a)
T min(const T &a, const T &b)
T mod_periodic(const T &a, const T &b)
T max(const T &a, const T &b)
T abs(const T &a)
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
static const mf::MultiFunction * get_multi_function(const bNode &bnode)
static void node_label(const bNodeTree *, const bNode *node, char *label, int label_maxncpy)
static void node_eval_elem(value_elem::ElemEvalParams &params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_declare(NodeDeclarationBuilder &b)
static void node_eval_inverse_elem(value_elem::InverseElemEvalParams &params)
static void node_eval_inverse(inverse_eval::InverseEvalParams &params)
static void node_update(bNodeTree *ntree, bNode *node)
static int safe_divide_round_i(const int a, const int b)
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)
void node_sock_label_clear(bNodeSocket *sock)
Definition node_util.cc:78
void node_sock_label(bNodeSocket *sock, const char *name)
Definition node_util.cc:73
const char * name
bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r_name)
void RNA_def_property_update_runtime(PropertyRNA *prop, RNAPropertyUpdateFunc func)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
const EnumPropertyItem rna_enum_node_integer_math_items[]
StructRNA * srna
void * first
struct bNodeSocket * next
int16_t custom1
ListBase inputs
Defines a node type.
Definition BKE_node.hh:238
NodeInverseElemEvalFunction eval_inverse_elem
Definition BKE_node.hh:403
NodeInverseEvalFunction eval_inverse
Definition BKE_node.hh:410
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
NodeElemEvalFunction eval_elem
Definition BKE_node.hh:397
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:351
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
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:281
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)
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238