Blender V4.5
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_string.h"
8
9#include "RNA_enum_types.hh"
10
11#include "UI_interface.hh"
12#include "UI_resources.hh"
13
15#include "NOD_rna_define.hh"
18
19#include "node_function_util.hh"
20
22
24{
25 b.is_function_node();
26 b.add_input<decl::Int>("Value");
27 b.add_input<decl::Int>("Value", "Value_001");
28 b.add_input<decl::Int>("Value", "Value_002");
29 b.add_output<decl::Int>("Value");
30};
31
32static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
33{
34 layout->prop(ptr, "operation", UI_ITEM_NONE, "", ICON_NONE);
35}
36
37static void node_update(bNodeTree *ntree, bNode *node)
38{
39 const bool one_input_ops = ELEM(
41 const bool three_input_ops = ELEM(node->custom1, NODE_INTEGER_MATH_MULTIPLY_ADD);
42
43 bNodeSocket *sockA = static_cast<bNodeSocket *>(node->inputs.first);
44 bNodeSocket *sockB = sockA->next;
45 bNodeSocket *sockC = sockB->next;
46
47 bke::node_set_socket_availability(*ntree, *sockB, !one_input_ops);
48 bke::node_set_socket_availability(*ntree, *sockC, three_input_ops);
49
53 switch (node->custom1) {
55 node_sock_label(sockA, N_("Value"));
56 node_sock_label(sockB, N_("Multiplier"));
57 node_sock_label(sockC, N_("Addend"));
58 break;
60 node_sock_label(sockA, N_("Base"));
61 node_sock_label(sockB, N_("Exponent"));
62 break;
63 }
64}
65
67 public:
68 std::string socket_name;
71 {
72 bNode &node = params.add_node("FunctionNodeIntegerMath");
74 params.update_and_connect_available_socket(node, socket_name);
75 }
76};
77
79{
80 if (!params.node_tree().typeinfo->validate_link(eNodeSocketDatatype(params.other_socket().type),
81 SOCK_INT))
82 {
83 return;
84 }
85
86 const bool is_integer = params.other_socket().type == SOCK_INT;
87 const int weight = is_integer ? 0 : -1;
88
89 /* Add socket A operations. */
91 item->identifier != nullptr;
92 item++)
93 {
94 if (item->name != nullptr && item->identifier[0] != '\0') {
95 params.add_item(CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, item->name),
96 SocketSearchOp{"Value", NodeIntegerMathOperation(item->value)},
97 weight);
98 }
99 }
100}
101
102static void node_label(const bNodeTree * /*ntree*/, const bNode *node, char *label, int maxlen)
103{
104 const char *name;
105 bool enum_label = RNA_enum_name(rna_enum_node_integer_math_items, node->custom1, &name);
106 if (!enum_label) {
107 name = "Unknown";
108 }
110}
111
112/* Derived from `divide_round_i` but fixed to be safe and handle negative inputs. */
113static int safe_divide_round_i(const int a, const int b)
114{
115 const int c = math::abs(b);
116 return (a >= 0) ? math::safe_divide((2 * a + c), (2 * c)) * math::sign(b) :
117 -math::safe_divide((2 * -a + c), (2 * c)) * math::sign(b);
118}
119
120static const mf::MultiFunction *get_multi_function(const bNode &bnode)
121{
123 static auto exec_preset = mf::build::exec_presets::AllSpanOrSingle();
124 static auto add_fn = mf::build::SI2_SO<int, int, int>(
125 "Add", [](int a, int b) { return a + b; }, exec_preset);
126 static auto sub_fn = mf::build::SI2_SO<int, int, int>(
127 "Subtract", [](int a, int b) { return a - b; }, exec_preset);
128 static auto multiply_fn = mf::build::SI2_SO<int, int, int>(
129 "Multiply", [](int a, int b) { return a * b; }, exec_preset);
130 static auto divide_fn = mf::build::SI2_SO<int, int, int>(
131 "Divide", [](int a, int b) { return math::safe_divide(a, b); }, exec_preset);
132 static auto divide_floor_fn = mf::build::SI2_SO<int, int, int>(
133 "Divide Floor",
134 [](int a, int b) { return (b != 0) ? divide_floor_i(a, b) : 0; },
135 exec_preset);
136 static auto divide_ceil_fn = mf::build::SI2_SO<int, int, int>(
137 "Divide Ceil",
138 [](int a, int b) { return (b != 0) ? -divide_floor_i(a, -b) : 0; },
139 exec_preset);
140 static auto divide_round_fn = mf::build::SI2_SO<int, int, int>(
141 "Divide Round", [](int a, int b) { return safe_divide_round_i(a, b); }, exec_preset);
142 static auto pow_fn = mf::build::SI2_SO<int, int, int>(
143 "Power", [](int a, int b) { return math::pow(a, b); }, exec_preset);
144 static auto madd_fn = mf::build::SI3_SO<int, int, int, int>(
145 "Multiply Add", [](int a, int b, int c) { return a * b + c; }, exec_preset);
146 static auto floored_mod_fn = mf::build::SI2_SO<int, int, int>(
147 "Floored Modulo",
148 [](int a, int b) { return b != 0 ? math::mod_periodic(a, b) : 0; },
149 exec_preset);
150 static auto mod_fn = mf::build::SI2_SO<int, int, int>(
151 "Modulo", [](int a, int b) { return b != 0 ? a % b : 0; }, exec_preset);
152 static auto abs_fn = mf::build::SI1_SO<int, int>(
153 "Absolute", [](int a) { return math::abs(a); }, exec_preset);
154 static auto sign_fn = mf::build::SI1_SO<int, int>(
155 "Sign", [](int a) { return math::sign(a); }, exec_preset);
156 static auto min_fn = mf::build::SI2_SO<int, int, int>(
157 "Minimum", [](int a, int b) { return math::min(a, b); }, exec_preset);
158 static auto max_fn = mf::build::SI2_SO<int, int, int>(
159 "Maximum", [](int a, int b) { return math::max(a, b); }, exec_preset);
160 static auto gcd_fn = mf::build::SI2_SO<int, int, int>(
161 "GCD", [](int a, int b) { return std::gcd(a, b); }, exec_preset);
162 static auto lcm_fn = mf::build::SI2_SO<int, int, int>(
163 "LCM", [](int a, int b) { return std::lcm(a, b); }, exec_preset);
164 static auto negate_fn = mf::build::SI1_SO<int, int>(
165 "Negate", [](int a) { return -a; }, exec_preset);
166
167 switch (operation) {
169 return &add_fn;
171 return &sub_fn;
173 return &multiply_fn;
175 return &divide_fn;
177 return &divide_floor_fn;
179 return &divide_ceil_fn;
181 return &divide_round_fn;
183 return &pow_fn;
185 return &madd_fn;
187 return &floored_mod_fn;
189 return &mod_fn;
191 return &abs_fn;
193 return &sign_fn;
195 return &min_fn;
197 return &max_fn;
199 return &gcd_fn;
201 return &lcm_fn;
203 return &negate_fn;
204 }
206 return nullptr;
207}
208
210{
211 const mf::MultiFunction *fn = get_multi_function(builder.node());
212 builder.set_matching_fn(fn);
213}
214
216{
217 using namespace value_elem;
219 switch (op) {
224 IntElem output_elem = params.get_input_elem<IntElem>("Value");
225 output_elem.merge(params.get_input_elem<IntElem>("Value_001"));
226 params.set_output_elem("Value", output_elem);
227 break;
228 }
229 default:
230 break;
231 }
232}
233
235{
237 switch (op) {
242 params.set_input_elem("Value", params.get_output_elem<value_elem::IntElem>("Value"));
243 break;
244 }
245 default:
246 break;
247 }
248}
249
251{
253 const StringRef first_input_id = "Value";
254 const StringRef second_input_id = "Value_001";
255 const StringRef output_id = "Value";
256 switch (op) {
258 params.set_input(first_input_id,
259 params.get_output<int>(output_id) - params.get_input<int>(second_input_id));
260 break;
261 }
263 params.set_input(first_input_id,
264 params.get_output<int>(output_id) + params.get_input<int>(second_input_id));
265 break;
266 }
268 params.set_input(first_input_id,
269 math::safe_divide(params.get_output<int>(output_id),
270 params.get_input<int>(second_input_id)));
271 break;
272 }
274 params.set_input(first_input_id,
275 params.get_output<int>(output_id) * params.get_input<int>(second_input_id));
276 break;
277 }
278 default: {
279 break;
280 }
281 }
282}
283
284static void node_rna(StructRNA *srna)
285{
286 PropertyRNA *prop;
287
288 prop = RNA_def_node_enum(srna,
289 "operation",
290 "Operation",
291 "",
297}
298
299static void node_register()
300{
301 static blender::bke::bNodeType ntype;
302
303 fn_node_type_base(&ntype, "FunctionNodeIntegerMath", FN_NODE_INTEGER_MATH);
304 ntype.ui_name = "Integer Math";
305 ntype.enum_name_legacy = "INTEGER_MATH";
307 ntype.declare = node_declare;
308 ntype.labelfunc = node_label;
309 ntype.updatefunc = node_update;
316
318
319 node_rna(ntype.rna_ext.srna);
320}
322
323} // namespace blender::nodes::node_fn_integer_math_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:439
#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 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:2748
void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, bool is_available)
Definition node.cc:5011
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, 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
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
Definition RNA_types.hh:909
void * first
struct bNodeSocket * next
int16_t custom1
ListBase inputs
Defines a node type.
Definition BKE_node.hh:226
NodeInverseElemEvalFunction eval_inverse_elem
Definition BKE_node.hh:396
NodeInverseEvalFunction eval_inverse
Definition BKE_node.hh:403
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:258
NodeElemEvalFunction eval_elem
Definition BKE_node.hh:390
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:344
const char * enum_name_legacy
Definition BKE_node.hh:235
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(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:269
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:4227