Blender V4.3
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_listbase.h"
8#include "BLI_string.h"
9#include "BLI_string_utf8.h"
10
11#include "RNA_enum_types.hh"
12
13#include "UI_interface.hh"
14#include "UI_resources.hh"
15
17#include "NOD_rna_define.hh"
20
21#include "node_function_util.hh"
22
24
26{
27 b.is_function_node();
28 b.add_input<decl::Int>("Value");
29 b.add_input<decl::Int>("Value", "Value_001");
30 b.add_input<decl::Int>("Value", "Value_002");
31 b.add_output<decl::Int>("Value");
32};
33
34static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
35{
36 uiItemR(layout, ptr, "operation", UI_ITEM_NONE, "", ICON_NONE);
37}
38
39static void node_update(bNodeTree *ntree, bNode *node)
40{
41 const bool one_input_ops = ELEM(
43 const bool three_input_ops = ELEM(node->custom1, NODE_INTEGER_MATH_MULTIPLY_ADD);
44
45 bNodeSocket *sockA = static_cast<bNodeSocket *>(node->inputs.first);
46 bNodeSocket *sockB = sockA->next;
47 bNodeSocket *sockC = sockB->next;
48
49 bke::node_set_socket_availability(ntree, sockB, !one_input_ops);
50 bke::node_set_socket_availability(ntree, sockC, three_input_ops);
51
55 switch (node->custom1) {
57 node_sock_label(sockA, N_("Value"));
58 node_sock_label(sockB, N_("Multiplier"));
59 node_sock_label(sockC, N_("Addend"));
60 break;
62 node_sock_label(sockA, N_("Base"));
63 node_sock_label(sockB, N_("Exponent"));
64 break;
65 }
66}
67
69 public:
70 std::string socket_name;
73 {
74 bNode &node = params.add_node("FunctionNodeIntegerMath");
75 node.custom1 = NodeIntegerMathOperation(operation);
76 params.update_and_connect_available_socket(node, socket_name);
77 }
78};
79
81{
82 if (!params.node_tree().typeinfo->validate_link(eNodeSocketDatatype(params.other_socket().type),
83 SOCK_INT))
84 {
85 return;
86 }
87
88 const bool is_integer = params.other_socket().type == SOCK_INT;
89 const int weight = is_integer ? 0 : -1;
90
91 /* Add socket A operations. */
93 item->identifier != nullptr;
94 item++)
95 {
96 if (item->name != nullptr && item->identifier[0] != '\0') {
97 params.add_item(IFACE_(item->name),
98 SocketSearchOp{"Value", NodeIntegerMathOperation(item->value)},
99 weight);
100 }
101 }
102}
103
104static void node_label(const bNodeTree * /*ntree*/, const bNode *node, char *label, int maxlen)
105{
106 const char *name;
107 bool enum_label = RNA_enum_name(rna_enum_node_integer_math_items, node->custom1, &name);
108 if (!enum_label) {
109 name = "Unknown";
110 }
112}
113
114/* Derived from `divide_round_i` but fixed to be safe and handle negative inputs. */
115static int safe_divide_round_i(const int a, const int b)
116{
117 const int c = math::abs(b);
118 return (a >= 0) ? math::safe_divide((2 * a + c), (2 * c)) * math::sign(b) :
119 -math::safe_divide((2 * -a + c), (2 * c)) * math::sign(b);
120}
121
122static const mf::MultiFunction *get_multi_function(const bNode &bnode)
123{
125 static auto exec_preset = mf::build::exec_presets::AllSpanOrSingle();
126 static auto add_fn = mf::build::SI2_SO<int, int, int>(
127 "Add", [](int a, int b) { return a + b; }, exec_preset);
128 static auto sub_fn = mf::build::SI2_SO<int, int, int>(
129 "Subtract", [](int a, int b) { return a - b; }, exec_preset);
130 static auto multiply_fn = mf::build::SI2_SO<int, int, int>(
131 "Multiply", [](int a, int b) { return a * b; }, exec_preset);
132 static auto divide_fn = mf::build::SI2_SO<int, int, int>(
133 "Divide", [](int a, int b) { return math::safe_divide(a, b); }, exec_preset);
134 static auto divide_floor_fn = mf::build::SI2_SO<int, int, int>(
135 "Divide Floor",
136 [](int a, int b) { return (b != 0) ? divide_floor_i(a, b) : 0; },
137 exec_preset);
138 static auto divide_ceil_fn = mf::build::SI2_SO<int, int, int>(
139 "Divide Ceil",
140 [](int a, int b) { return (b != 0) ? -divide_floor_i(a, -b) : 0; },
141 exec_preset);
142 static auto divide_round_fn = mf::build::SI2_SO<int, int, int>(
143 "Divide Round", [](int a, int b) { return safe_divide_round_i(a, b); }, exec_preset);
144 static auto pow_fn = mf::build::SI2_SO<int, int, int>(
145 "Power", [](int a, int b) { return math::pow(a, b); }, exec_preset);
146 static auto madd_fn = mf::build::SI3_SO<int, int, int, int>(
147 "Multiply Add", [](int a, int b, int c) { return a * b + c; }, exec_preset);
148 static auto floored_mod_fn = mf::build::SI2_SO<int, int, int>(
149 "Floored Modulo",
150 [](int a, int b) { return b != 0 ? math::mod_periodic(a, b) : 0; },
151 exec_preset);
152 static auto mod_fn = mf::build::SI2_SO<int, int, int>(
153 "Modulo", [](int a, int b) { return b != 0 ? a % b : 0; }, exec_preset);
154 static auto abs_fn = mf::build::SI1_SO<int, int>(
155 "Absolute", [](int a) { return math::abs(a); }, exec_preset);
156 static auto sign_fn = mf::build::SI1_SO<int, int>(
157 "Sign", [](int a) { return math::sign(a); }, exec_preset);
158 static auto min_fn = mf::build::SI2_SO<int, int, int>(
159 "Minimum", [](int a, int b) { return math::min(a, b); }, exec_preset);
160 static auto max_fn = mf::build::SI2_SO<int, int, int>(
161 "Maximum", [](int a, int b) { return math::max(a, b); }, exec_preset);
162 static auto gcd_fn = mf::build::SI2_SO<int, int, int>(
163 "GCD", [](int a, int b) { return std::gcd(a, b); }, exec_preset);
164 static auto lcm_fn = mf::build::SI2_SO<int, int, int>(
165 "LCM", [](int a, int b) { return std::lcm(a, b); }, exec_preset);
166 static auto negate_fn = mf::build::SI1_SO<int, int>(
167 "Negate", [](int a) { return -a; }, exec_preset);
168
169 switch (operation) {
171 return &add_fn;
173 return &sub_fn;
175 return &multiply_fn;
177 return &divide_fn;
179 return &divide_floor_fn;
181 return &divide_ceil_fn;
183 return &divide_round_fn;
185 return &pow_fn;
187 return &madd_fn;
189 return &floored_mod_fn;
191 return &mod_fn;
193 return &abs_fn;
195 return &sign_fn;
197 return &min_fn;
199 return &max_fn;
201 return &gcd_fn;
203 return &lcm_fn;
205 return &negate_fn;
206 }
208 return nullptr;
209}
210
212{
213 const mf::MultiFunction *fn = get_multi_function(builder.node());
214 builder.set_matching_fn(fn);
215}
216
218{
219 using namespace value_elem;
221 switch (op) {
226 IntElem output_elem = params.get_input_elem<IntElem>("Value");
227 output_elem.merge(params.get_input_elem<IntElem>("Value_001"));
228 params.set_output_elem("Value", output_elem);
229 break;
230 }
231 default:
232 break;
233 }
234}
235
237{
239 switch (op) {
244 params.set_input_elem("Value", params.get_output_elem<value_elem::IntElem>("Value"));
245 break;
246 }
247 default:
248 break;
249 }
250}
251
253{
255 const StringRef first_input_id = "Value";
256 const StringRef second_input_id = "Value_001";
257 const StringRef output_id = "Value";
258 switch (op) {
260 params.set_input(first_input_id,
261 params.get_output<int>(output_id) - params.get_input<int>(second_input_id));
262 break;
263 }
265 params.set_input(first_input_id,
266 params.get_output<int>(output_id) + params.get_input<int>(second_input_id));
267 break;
268 }
270 params.set_input(first_input_id,
271 math::safe_divide(params.get_output<int>(output_id),
272 params.get_input<int>(second_input_id)));
273 break;
274 }
276 params.set_input(first_input_id,
277 params.get_output<int>(output_id) * params.get_input<int>(second_input_id));
278 break;
279 }
280 default: {
281 break;
282 }
283 }
284}
285
286static void node_rna(StructRNA *srna)
287{
288 PropertyRNA *prop;
289
290 prop = RNA_def_node_enum(srna,
291 "operation",
292 "Operation",
293 "",
299}
300
301static void node_register()
302{
303 static blender::bke::bNodeType ntype;
304
305 fn_node_type_base(&ntype, FN_NODE_INTEGER_MATH, "Integer Math", NODE_CLASS_CONVERTER);
306 ntype.declare = node_declare;
307 ntype.labelfunc = node_label;
308 ntype.updatefunc = node_update;
315
317
318 node_rna(ntype.rna_ext.srna);
319}
321
322} // namespace blender::nodes::node_fn_integer_math_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:410
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define ELEM(...)
#define BLT_I18NCONTEXT_ID_NODETREE
#define CTX_IFACE_(context, msgid)
#define IFACE_(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 uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
void set_matching_fn(const mf::MultiFunction *fn)
local_group_size(16, 16) .push_constant(Type b
const char * label
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
MINLINE int divide_floor_i(int a, int b)
void node_set_socket_availability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
Definition node.cc:3911
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
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_eval_elem(value_elem::ElemEvalParams &params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_label(const bNodeTree *, const bNode *node, char *label, int maxlen)
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, int type, const char *name, short nclass)
void node_sock_label_clear(bNodeSocket *sock)
Definition node_util.cc:82
void node_sock_label(bNodeSocket *sock, const char *name)
Definition node_util.cc:77
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[]
const char * identifier
Definition RNA_types.hh:506
StructRNA * srna
Definition RNA_types.hh:780
struct bNodeSocket * next
int16_t custom1
Defines a node type.
Definition BKE_node.hh:218
NodeInverseElemEvalFunction eval_inverse_elem
Definition BKE_node.hh:378
NodeInverseEvalFunction eval_inverse
Definition BKE_node.hh:385
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:249
NodeElemEvalFunction eval_elem
Definition BKE_node.hh:372
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:336
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
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:257
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126