Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/function/nodes')
-rw-r--r--source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc (renamed from source/blender/nodes/function/nodes/node_fn_random_float.cc)13
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_special_characters.cc74
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_string.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc299
-rw-r--r--source/blender/nodes/function/nodes/node_fn_rotate_euler.cc138
-rw-r--r--source/blender/nodes/function/nodes/node_fn_string_length.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_string_substring.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_value_to_string.cc1
11 files changed, 525 insertions, 6 deletions
diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
index 1bd39aacdca..7f6f554ba93 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
@@ -20,8 +20,9 @@
namespace blender::nodes {
-static void fn_node_random_float_declare(NodeDeclarationBuilder &b)
+static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Min").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("Max").default_value(1.0f).min(-10000.0f).max(10000.0f);
b.add_input<decl::Int>("Seed").min(-10000).max(10000);
@@ -67,19 +68,19 @@ class RandomFloatFunction : public blender::fn::MultiFunction {
}
};
-static void fn_node_random_float_build_multi_function(
+static void fn_node_legacy_random_float_build_multi_function(
blender::nodes::NodeMultiFunctionBuilder &builder)
{
static RandomFloatFunction fn;
builder.set_matching_fn(fn);
}
-void register_node_type_fn_random_float()
+void register_node_type_fn_legacy_random_float()
{
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_RANDOM_FLOAT, "Random Float", 0, 0);
- ntype.declare = blender::nodes::fn_node_random_float_declare;
- ntype.build_multi_function = fn_node_random_float_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_LEGACY_RANDOM_FLOAT, "Random Float", 0, 0);
+ ntype.declare = blender::nodes::fn_node_legacy_random_float_declare;
+ ntype.build_multi_function = fn_node_legacy_random_float_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
index b71ee092de6..d10490bb2ee 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -28,6 +28,7 @@ namespace blender::nodes {
static void fn_node_boolean_math_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Bool>("Boolean", "Boolean");
b.add_input<decl::Bool>("Boolean", "Boolean_001");
b.add_output<decl::Bool>("Boolean");
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
index 4f4830afabc..9736c52e895 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
@@ -30,6 +30,7 @@ namespace blender::nodes {
static void fn_node_float_compare_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("A").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("B").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("Epsilon").default_value(0.001f).min(-10000.0f).max(10000.0f);
diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
index e59c78d2c04..8bb5dafff8a 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
@@ -29,6 +29,7 @@ namespace blender::nodes {
static void fn_node_float_to_int_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Float");
b.add_output<decl::Int>("Integer");
};
diff --git a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
new file mode 100644
index 00000000000..11c64d3f694
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
@@ -0,0 +1,74 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_function_util.hh"
+
+namespace blender::nodes {
+
+static void fn_node_input_special_characters_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::String>("Line Break");
+ b.add_output<decl::String>("Tab");
+};
+
+class MF_SpecialCharacters : public fn::MultiFunction {
+ public:
+ MF_SpecialCharacters()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Special Characters"};
+ signature.single_output<std::string>("Line Break");
+ signature.single_output<std::string>("Tab");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ MutableSpan<std::string> lb = params.uninitialized_single_output<std::string>(0, "Line Break");
+ MutableSpan<std::string> tab = params.uninitialized_single_output<std::string>(1, "Tab");
+
+ for (const int i : mask) {
+ new (&lb[i]) std::string("\n");
+ new (&tab[i]) std::string("\t");
+ }
+ }
+};
+
+static void fn_node_input_special_characters_build_multi_function(
+ NodeMultiFunctionBuilder &builder)
+{
+ static MF_SpecialCharacters special_characters_fn;
+ builder.set_matching_fn(special_characters_fn);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_input_special_characters()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(
+ &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT, 0);
+ ntype.declare = blender::nodes::fn_node_input_special_characters_declare;
+ ntype.build_multi_function =
+ blender::nodes::fn_node_input_special_characters_build_multi_function;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc
index 4a8e898fb9b..704ae9d900c 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc
@@ -23,6 +23,7 @@ namespace blender::nodes {
static void fn_node_input_string_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_output<decl::String>("String");
};
diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc
new file mode 100644
index 00000000000..53ca77aab0c
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -0,0 +1,299 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+// #include "BLI_hash.h"
+#include "BLI_noise.hh"
+
+#include "node_function_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+static void fn_node_random_value_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>("Min").supports_field();
+ b.add_input<decl::Vector>("Max").default_value({1.0f, 1.0f, 1.0f}).supports_field();
+ b.add_input<decl::Float>("Min", "Min_001").supports_field();
+ b.add_input<decl::Float>("Max", "Max_001").default_value(1.0f).supports_field();
+ b.add_input<decl::Int>("Min", "Min_002").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Int>("Max", "Max_002")
+ .default_value(100)
+ .min(-100000)
+ .max(100000)
+ .supports_field();
+ b.add_input<decl::Float>("Probability")
+ .min(0.0f)
+ .max(1.0f)
+ .default_value(0.5f)
+ .subtype(PROP_FACTOR)
+ .supports_field();
+ b.add_input<decl::Int>("ID").implicit_field();
+ b.add_input<decl::Int>("Seed").default_value(0).min(-10000).max(10000).supports_field();
+
+ b.add_output<decl::Vector>("Value").dependent_field();
+ b.add_output<decl::Float>("Value", "Value_001").dependent_field();
+ b.add_output<decl::Int>("Value", "Value_002").dependent_field();
+ b.add_output<decl::Bool>("Value", "Value_003").dependent_field();
+}
+
+static void fn_node_random_value_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+}
+
+static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeRandomValue *data = (NodeRandomValue *)MEM_callocN(sizeof(NodeRandomValue), __func__);
+ data->data_type = CD_PROP_FLOAT;
+ node->storage = data;
+}
+
+static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeRandomValue &storage = *(const NodeRandomValue *)node->storage;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ bNodeSocket *sock_min_vector = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *sock_max_vector = sock_min_vector->next;
+ bNodeSocket *sock_min_float = sock_max_vector->next;
+ bNodeSocket *sock_max_float = sock_min_float->next;
+ bNodeSocket *sock_min_int = sock_max_float->next;
+ bNodeSocket *sock_max_int = sock_min_int->next;
+ bNodeSocket *sock_probability = sock_max_int->next;
+
+ bNodeSocket *sock_out_vector = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *sock_out_float = sock_out_vector->next;
+ bNodeSocket *sock_out_int = sock_out_float->next;
+ bNodeSocket *sock_out_bool = sock_out_int->next;
+
+ nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(sock_probability, data_type == CD_PROP_BOOL);
+
+ nodeSetSocketAvailability(sock_out_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(sock_out_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(sock_out_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(sock_out_bool, data_type == CD_PROP_BOOL);
+}
+
+class RandomVectorFunction : public fn::MultiFunction {
+ public:
+ RandomVectorFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Random Value"};
+ signature.single_input<float3>("Min");
+ signature.single_input<float3>("Max");
+ signature.single_input<int>("ID");
+ signature.single_input<int>("Seed");
+ signature.single_output<float3>("Value");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &min_values = params.readonly_single_input<float3>(0, "Min");
+ const VArray<float3> &max_values = params.readonly_single_input<float3>(1, "Max");
+ const VArray<int> &ids = params.readonly_single_input<int>(2, "ID");
+ const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed");
+ MutableSpan<float3> values = params.uninitialized_single_output<float3>(4, "Value");
+
+ for (int64_t i : mask) {
+ const float3 min_value = min_values[i];
+ const float3 max_value = max_values[i];
+ const int seed = seeds[i];
+ const int id = ids[i];
+
+ const float x = noise::hash_to_float(seed, id, 0);
+ const float y = noise::hash_to_float(seed, id, 1);
+ const float z = noise::hash_to_float(seed, id, 2);
+
+ values[i] = float3(x, y, z) * (max_value - min_value) + min_value;
+ }
+ }
+};
+
+class RandomFloatFunction : public fn::MultiFunction {
+ public:
+ RandomFloatFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Random Value"};
+ signature.single_input<float>("Min");
+ signature.single_input<float>("Max");
+ signature.single_input<int>("ID");
+ signature.single_input<int>("Seed");
+ signature.single_output<float>("Value");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float> &min_values = params.readonly_single_input<float>(0, "Min");
+ const VArray<float> &max_values = params.readonly_single_input<float>(1, "Max");
+ const VArray<int> &ids = params.readonly_single_input<int>(2, "ID");
+ const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed");
+ MutableSpan<float> values = params.uninitialized_single_output<float>(4, "Value");
+
+ for (int64_t i : mask) {
+ const float min_value = min_values[i];
+ const float max_value = max_values[i];
+ const int seed = seeds[i];
+ const int id = ids[i];
+
+ const float value = noise::hash_to_float(seed, id);
+ values[i] = value * (max_value - min_value) + min_value;
+ }
+ }
+};
+
+class RandomIntFunction : public fn::MultiFunction {
+ public:
+ RandomIntFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Random Value"};
+ signature.single_input<int>("Min");
+ signature.single_input<int>("Max");
+ signature.single_input<int>("ID");
+ signature.single_input<int>("Seed");
+ signature.single_output<int>("Value");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<int> &min_values = params.readonly_single_input<int>(0, "Min");
+ const VArray<int> &max_values = params.readonly_single_input<int>(1, "Max");
+ const VArray<int> &ids = params.readonly_single_input<int>(2, "ID");
+ const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed");
+ MutableSpan<int> values = params.uninitialized_single_output<int>(4, "Value");
+
+ for (int64_t i : mask) {
+ const float min_value = min_values[i];
+ const float max_value = max_values[i];
+ const int seed = seeds[i];
+ const int id = ids[i];
+
+ const float value = noise::hash_to_float(id, seed);
+ values[i] = round_fl_to_int(value * (max_value - min_value) + min_value);
+ }
+ }
+};
+
+class RandomBoolFunction : public fn::MultiFunction {
+ public:
+ RandomBoolFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Random Value"};
+ signature.single_input<float>("Probability");
+ signature.single_input<int>("ID");
+ signature.single_input<int>("Seed");
+ signature.single_output<bool>("Value");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float> &probabilities = params.readonly_single_input<float>(0, "Probability");
+ const VArray<int> &ids = params.readonly_single_input<int>(1, "ID");
+ const VArray<int> &seeds = params.readonly_single_input<int>(2, "Seed");
+ MutableSpan<bool> values = params.uninitialized_single_output<bool>(3, "Value");
+
+ for (int64_t i : mask) {
+ const int seed = seeds[i];
+ const int id = ids[i];
+ const float probability = probabilities[i];
+ values[i] = noise::hash_to_float(id, seed) <= probability;
+ }
+ }
+};
+
+static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const NodeRandomValue &storage = *(const NodeRandomValue *)builder.node().storage;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ switch (data_type) {
+ case CD_PROP_FLOAT3: {
+ static RandomVectorFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case CD_PROP_FLOAT: {
+ static RandomFloatFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case CD_PROP_INT32: {
+ static RandomIntFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case CD_PROP_BOOL: {
+ static RandomBoolFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_random_value()
+{
+ static bNodeType ntype;
+ fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER, 0);
+ node_type_init(&ntype, blender::nodes::fn_node_random_value_init);
+ node_type_update(&ntype, blender::nodes::fn_node_random_value_update);
+ ntype.draw_buttons = blender::nodes::fn_node_random_value_layout;
+ ntype.declare = blender::nodes::fn_node_random_value_declare;
+ ntype.build_multi_function = blender::nodes::fn_node_random_value_build_multi_function;
+ node_type_storage(
+ &ntype, "NodeRandomValue", node_free_standard_storage, node_copy_standard_storage);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
new file mode 100644
index 00000000000..cbae1648663
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
@@ -0,0 +1,138 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_function_util.hh"
+
+namespace blender::nodes {
+static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER).hide_value();
+ b.add_input<decl::Vector>("Rotate By").subtype(PROP_EULER);
+ b.add_input<decl::Vector>("Axis").default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
+ b.add_input<decl::Float>("Angle").subtype(PROP_ANGLE);
+ b.add_output<decl::Vector>("Rotation");
+};
+
+static void fn_node_rotate_euler_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *rotate_by_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1));
+ bNodeSocket *axis_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2));
+ bNodeSocket *angle_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 3));
+
+ nodeSetSocketAvailability(rotate_by_socket,
+ ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER));
+ nodeSetSocketAvailability(axis_socket,
+ ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE));
+ nodeSetSocketAvailability(angle_socket,
+ ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE));
+}
+
+static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &bnode)
+{
+ static fn::CustomMF_SI_SI_SO<float3, float3, float3> obj_euler_rot{
+ "Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ eul_to_mat3(rot_mat, rotation);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, rot_mat, input_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> obj_AA_rot{
+ "Rotate Euler by AxisAngle/Object",
+ [](const float3 &input, const float3 &axis, float angle) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ axis_angle_to_mat3(rot_mat, axis, angle);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, rot_mat, input_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ static fn::CustomMF_SI_SI_SO<float3, float3, float3> point_euler_rot{
+ "Rotate Euler by Euler/Point", [](const float3 &input, const float3 &rotation) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ eul_to_mat3(rot_mat, rotation);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, input_mat, rot_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> point_AA_rot{
+ "Rotate Euler by AxisAngle/Point", [](const float3 &input, const float3 &axis, float angle) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ axis_angle_to_mat3(rot_mat, axis, angle);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, input_mat, rot_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ short type = bnode.custom1;
+ short space = bnode.custom2;
+ if (type == FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE) {
+ return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_AA_rot : &point_AA_rot;
+ }
+ if (type == FN_NODE_ROTATE_EULER_TYPE_EULER) {
+ return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_euler_rot : &point_euler_rot;
+ }
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static void fn_node_rotate_euler_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
+ builder.set_matching_fn(fn);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_rotate_euler()
+{
+ static bNodeType ntype;
+ fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER, 0);
+ ntype.declare = blender::nodes::fn_node_rotate_euler_declare;
+ ntype.draw_buttons = blender::nodes::fn_node_rotate_euler_layout;
+ node_type_update(&ntype, blender::nodes::fn_node_rotate_euler_update);
+ ntype.build_multi_function = blender::nodes::fn_node_rotate_euler_build_multi_function;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_string_length.cc b/source/blender/nodes/function/nodes/node_fn_string_length.cc
index a0f85dfd2bf..89038629c3c 100644
--- a/source/blender/nodes/function/nodes/node_fn_string_length.cc
+++ b/source/blender/nodes/function/nodes/node_fn_string_length.cc
@@ -24,6 +24,7 @@ namespace blender::nodes {
static void fn_node_string_length_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::String>("String");
b.add_output<decl::Int>("Length");
};
diff --git a/source/blender/nodes/function/nodes/node_fn_string_substring.cc b/source/blender/nodes/function/nodes/node_fn_string_substring.cc
index 55a01093ae9..b91171923d6 100644
--- a/source/blender/nodes/function/nodes/node_fn_string_substring.cc
+++ b/source/blender/nodes/function/nodes/node_fn_string_substring.cc
@@ -22,6 +22,7 @@ namespace blender::nodes {
static void fn_node_string_substring_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::String>("String");
b.add_input<decl::Int>("Position");
b.add_input<decl::Int>("Length").min(0);
diff --git a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
index c1e6373cb6d..56206af2eb2 100644
--- a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
@@ -21,6 +21,7 @@ namespace blender::nodes {
static void fn_node_value_to_string_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Value");
b.add_input<decl::Int>("Decimals").min(0);
b.add_output<decl::String>("String");