Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/function/nodes/node_fn_random.cc
- This file was added.
| /* | |||||
| * 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. | |||||
| */ | |||||
| /* | |||||
| * 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 "node_function_util.hh" | |||||
| #include "UI_interface.h" | |||||
| #include "UI_resources.h" | |||||
| namespace blender::nodes { | |||||
| static void fn_node_random_declare(NodeDeclarationBuilder &b) | |||||
| { | |||||
| b.add_input<decl::Vector>("Min"); | |||||
| b.add_input<decl::Vector>("Max").default_value({1.0f, 1.0f, 1.0f}); | |||||
| b.add_input<decl::Float>("Min", "Min_001"); | |||||
| b.add_input<decl::Float>("Max", "Max_001").default_value(1.0f); | |||||
| b.add_input<decl::Int>("Min", "Min_002").min(-100000).max(100000); | |||||
| b.add_input<decl::Int>("Max", "Max_002").default_value(100).min(-100000).max(100000); | |||||
| b.add_input<decl::Int>("Seed").default_value(0).min(-10000).max(10000); | |||||
| b.add_output<decl::Vector>("Value"); | |||||
| b.add_output<decl::Float>("Value", "Value_001"); | |||||
| b.add_output<decl::Int>("Value", "Value_002"); | |||||
| b.add_output<decl::Bool>("Value", "Value_003"); | |||||
| } | |||||
| static void fn_node_random_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) | |||||
| { | |||||
| uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); | |||||
| } | |||||
| static void fn_node_random_init(bNodeTree *UNUSED(tree), bNode *node) | |||||
| { | |||||
| NodeRandom *data = (NodeRandom *)MEM_callocN(sizeof(NodeRandom), __func__); | |||||
| data->data_type = CD_PROP_FLOAT; | |||||
| node->storage = data; | |||||
| } | |||||
| static void fn_node_random_update(bNodeTree *UNUSED(ntree), bNode *node) | |||||
| { | |||||
| const NodeRandom &storage = *(const NodeRandom *)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_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_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 blender::fn::MultiFunction { | |||||
| public: | |||||
| RandomVectorFunction() | |||||
| { | |||||
| static blender::fn::MFSignature signature = create_signature(); | |||||
| this->set_signature(&signature); | |||||
| } | |||||
| static blender::fn::MFSignature create_signature() | |||||
| { | |||||
| blender::fn::MFSignatureBuilder signature{"Random"}; | |||||
| signature.single_input<float3>("Min"); | |||||
| signature.single_input<float3>("Max"); | |||||
| signature.single_input<int>("Seed"); | |||||
| signature.single_output<float3>("Value"); | |||||
| return signature.build(); | |||||
| } | |||||
| void call(blender::IndexMask mask, | |||||
| blender::fn::MFParams params, | |||||
| blender::fn::MFContext UNUSED(context)) const override | |||||
| { | |||||
| const blender::VArray<float3> &min_values = params.readonly_single_input<float3>(0, "Min"); | |||||
| const blender::VArray<float3> &max_values = params.readonly_single_input<float3>(1, "Max"); | |||||
| const blender::VArray<int> &seeds = params.readonly_single_input<int>(2, "Seed"); | |||||
| blender::MutableSpan<float3> values = params.uninitialized_single_output<float3>(3, "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 float x = BLI_hash_int_3d_to_float(seed, i, 435109); | |||||
| const float y = BLI_hash_int_3d_to_float(seed, i, 380867); | |||||
| const float z = BLI_hash_int_3d_to_float(seed, i, 1059217); | |||||
| values[i] = float3(x, y, z) * (max_value - min_value) + min_value; | |||||
| } | |||||
| } | |||||
| }; | |||||
| class RandomFloatFunction : public blender::fn::MultiFunction { | |||||
| public: | |||||
| RandomFloatFunction() | |||||
| { | |||||
| static blender::fn::MFSignature signature = create_signature(); | |||||
| this->set_signature(&signature); | |||||
| } | |||||
| static blender::fn::MFSignature create_signature() | |||||
| { | |||||
| blender::fn::MFSignatureBuilder signature{"Random"}; | |||||
| signature.single_input<float>("Min"); | |||||
| signature.single_input<float>("Max"); | |||||
| signature.single_input<int>("Seed"); | |||||
| signature.single_output<float>("Value"); | |||||
| return signature.build(); | |||||
| } | |||||
| void call(blender::IndexMask mask, | |||||
| blender::fn::MFParams params, | |||||
| blender::fn::MFContext UNUSED(context)) const override | |||||
| { | |||||
| const blender::VArray<float> &min_values = params.readonly_single_input<float>(0, "Min"); | |||||
| const blender::VArray<float> &max_values = params.readonly_single_input<float>(1, "Max"); | |||||
| const blender::VArray<int> &seeds = params.readonly_single_input<int>(2, "Seed"); | |||||
| blender::MutableSpan<float> values = params.uninitialized_single_output<float>(3, "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 float value = BLI_hash_int_01(static_cast<uint32_t>(seed)); | |||||
| values[i] = value * (max_value - min_value) + min_value; | |||||
| } | |||||
| } | |||||
| }; | |||||
| class RandomIntFunction : public blender::fn::MultiFunction { | |||||
| public: | |||||
| RandomIntFunction() | |||||
| { | |||||
| static blender::fn::MFSignature signature = create_signature(); | |||||
| this->set_signature(&signature); | |||||
| } | |||||
| static blender::fn::MFSignature create_signature() | |||||
| { | |||||
| blender::fn::MFSignatureBuilder signature{"Random"}; | |||||
| signature.single_input<int>("Min"); | |||||
| signature.single_input<int>("Max"); | |||||
| signature.single_input<int>("Seed"); | |||||
| signature.single_output<int>("Value"); | |||||
| return signature.build(); | |||||
| } | |||||
| void call(blender::IndexMask mask, | |||||
| blender::fn::MFParams params, | |||||
| blender::fn::MFContext UNUSED(context)) const override | |||||
| { | |||||
| const blender::VArray<int> &min_values = params.readonly_single_input<int>(0, "Min"); | |||||
| const blender::VArray<int> &max_values = params.readonly_single_input<int>(1, "Max"); | |||||
| const blender::VArray<int> &seeds = params.readonly_single_input<int>(2, "Seed"); | |||||
| blender::MutableSpan<int> values = params.uninitialized_single_output<int>(3, "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 float value = BLI_hash_int_01(static_cast<uint32_t>(seed)); | |||||
| values[i] = round_fl_to_int(value * (max_value - min_value) + min_value); | |||||
| } | |||||
| } | |||||
| }; | |||||
| class RandomBoolFunction : public blender::fn::MultiFunction { | |||||
| public: | |||||
| RandomBoolFunction() | |||||
| { | |||||
| static blender::fn::MFSignature signature = create_signature(); | |||||
| this->set_signature(&signature); | |||||
| } | |||||
| static blender::fn::MFSignature create_signature() | |||||
| { | |||||
| blender::fn::MFSignatureBuilder signature{"Random"}; | |||||
| signature.single_input<int>("Seed"); | |||||
| signature.single_output<bool>("Value"); | |||||
| return signature.build(); | |||||
| } | |||||
| void call(blender::IndexMask mask, | |||||
| blender::fn::MFParams params, | |||||
| blender::fn::MFContext UNUSED(context)) const override | |||||
| { | |||||
| const blender::VArray<int> &seeds = params.readonly_single_input<int>(2, "Seed"); | |||||
| blender::MutableSpan<bool> values = params.uninitialized_single_output<bool>(3, "Value"); | |||||
| for (int64_t i : mask) { | |||||
| const int seed = seeds[i]; | |||||
| values[i] = BLI_hash_int_2d_to_float(i, seed) > 0.5f; | |||||
| } | |||||
| } | |||||
| }; | |||||
| static void fn_node_random_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) | |||||
| { | |||||
| const NodeRandom &storage = *(const NodeRandom *)builder.node().storage; | |||||
| const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); | |||||
| if (data_type == CD_PROP_FLOAT3) { | |||||
| static RandomVectorFunction fn; | |||||
| builder.set_matching_fn(fn); | |||||
| } | |||||
| else if (data_type == CD_PROP_FLOAT) { | |||||
| static RandomFloatFunction fn; | |||||
| builder.set_matching_fn(fn); | |||||
| } | |||||
| else if (data_type == CD_PROP_INT32) { | |||||
| static RandomIntFunction fn; | |||||
| builder.set_matching_fn(fn); | |||||
| } | |||||
| else if (data_type == CD_PROP_BOOL) { | |||||
| static RandomBoolFunction fn; | |||||
| builder.set_matching_fn(fn); | |||||
| } | |||||
| else { | |||||
| BLI_assert_unreachable("Unavailable Datatype Specified"); | |||||
| } | |||||
| } | |||||
| } // namespace blender::nodes | |||||
| void register_node_type_fn_random() | |||||
| { | |||||
| static bNodeType ntype; | |||||
| fn_node_type_base(&ntype, FN_NODE_RANDOM, "Random", NODE_CLASS_CONVERTER, 0); | |||||
| node_type_init(&ntype, blender::nodes::fn_node_random_init); | |||||
| node_type_update(&ntype, blender::nodes::fn_node_random_update); | |||||
| ntype.draw_buttons = blender::nodes::fn_node_random_layout; | |||||
| ntype.declare = blender::nodes::fn_node_random_declare; | |||||
| ntype.build_multi_function = blender::nodes::fn_node_random_build_multi_function; | |||||
| node_type_storage(&ntype, "NodeRandom", node_free_standard_storage, node_copy_standard_storage); | |||||
| nodeRegisterType(&ntype); | |||||
| } | |||||