From 2ddb3dc617a5ad3dd5882cde8c088127bd57f916 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 16 Jul 2020 13:38:23 +0200 Subject: Nodes: support default function for partially implemented nodes --- .../blenkernel/BKE_node_tree_multi_function.hh | 27 ++++++++---- .../blenkernel/intern/node_tree_multi_function.cc | 48 ++++++++++++++++++---- .../blender/functions/FN_multi_function_builder.hh | 11 +++++ .../functions/intern/multi_function_builder.cc | 29 +++++++++++++ 4 files changed, 98 insertions(+), 17 deletions(-) diff --git a/source/blender/blenkernel/BKE_node_tree_multi_function.hh b/source/blender/blenkernel/BKE_node_tree_multi_function.hh index dcbd551591f..95a6c61da7f 100644 --- a/source/blender/blenkernel/BKE_node_tree_multi_function.hh +++ b/source/blender/blenkernel/BKE_node_tree_multi_function.hh @@ -88,6 +88,7 @@ class MFNetworkTreeMap { void add(const DSocket &dsocket, fn::MFSocket &socket) { BLI_assert(dsocket.is_input() == socket.is_input()); + BLI_assert(dsocket.is_input() || sockets_by_dsocket_id_[dsocket.id()].size() == 0); sockets_by_dsocket_id_[dsocket.id()].append(&socket); } @@ -98,6 +99,8 @@ class MFNetworkTreeMap { void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket) { + /* There can be at most one matching output socket. */ + BLI_assert(sockets_by_dsocket_id_[dsocket.id()].size() == 0); sockets_by_dsocket_id_[dsocket.id()].append(&socket); } @@ -319,11 +322,11 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase { */ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { private: - const DNode &node_; + const DNode &dnode_; public: - NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DNode &node) - : MFNetworkBuilderBase(common), node_(node) + NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DNode &dnode) + : MFNetworkBuilderBase(common), dnode_(dnode) { } @@ -331,12 +334,20 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { * Tells the builder to build a function that corresponds to the node that is being built. It * will try to match up sockets. */ - template void construct_and_set_matching_fn(Args &&... args) + template T &construct_and_set_matching_fn(Args &&... args) { - const fn::MultiFunction &function = this->construct_fn(std::forward(args)...); + T &function = this->construct_fn(std::forward(args)...); this->set_matching_fn(function); + return function; } + const fn::MultiFunction &get_not_implemented_fn() + { + return this->get_default_fn("Not Implemented (" + dnode_.name() + ")"); + } + + const fn::MultiFunction &get_default_fn(StringRef name); + /** * Tells the builder that the given function corresponds to the node that is being built. It will * try to match up sockets. For that it skips unavailable and non-data sockets. @@ -344,7 +355,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { void set_matching_fn(const fn::MultiFunction &function) { fn::MFFunctionNode &node = common_.network.add_function(function); - common_.network_map.add_try_match(node_, node); + common_.network_map.add_try_match(dnode_, node); } /** @@ -352,7 +363,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { */ bNode &bnode() { - return *node_.node_ref().bnode(); + return *dnode_.node_ref().bnode(); } /** @@ -360,7 +371,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { */ const DNode &dnode() const { - return node_; + return dnode_; } }; diff --git a/source/blender/blenkernel/intern/node_tree_multi_function.cc b/source/blender/blenkernel/intern/node_tree_multi_function.cc index 4e505db9b9d..942f8e9a87a 100644 --- a/source/blender/blenkernel/intern/node_tree_multi_function.cc +++ b/source/blender/blenkernel/intern/node_tree_multi_function.cc @@ -31,6 +31,35 @@ static std::optional try_get_multi_function_data_type_of_socket( return bsocket->typeinfo->get_mf_data_type(); } +const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name) +{ + Vector input_types; + Vector output_types; + + for (const DInputSocket *dsocket : dnode_.inputs()) { + if (dsocket->is_available()) { + std::optional data_type = try_get_multi_function_data_type_of_socket( + dsocket->bsocket()); + if (data_type.has_value()) { + input_types.append(*data_type); + } + } + } + for (const DOutputSocket *dsocket : dnode_.outputs()) { + if (dsocket->is_available()) { + std::optional data_type = try_get_multi_function_data_type_of_socket( + dsocket->bsocket()); + if (data_type.has_value()) { + output_types.append(*data_type); + } + } + } + + const fn::MultiFunction &fn = this->construct_fn( + name, input_types, output_types); + return fn; +} + static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &dnode) { constexpr uint stack_capacity = 10; @@ -138,20 +167,21 @@ static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common, } if (from_dsockets.size() == 1) { - if (is_multi_function_data_socket(from_dsockets[0]->bsocket())) { - return &common.network_map.lookup(*from_dsockets[0]); - } - else { + const DOutputSocket &from_dsocket = *from_dsockets[0]; + if (!from_dsocket.is_available()) { return nullptr; } + if (is_multi_function_data_socket(from_dsocket.bsocket())) { + return &common.network_map.lookup(from_dsocket); + } + return nullptr; } else { - if (is_multi_function_data_socket(from_group_inputs[0]->bsocket())) { - return &common.network_map.lookup(*from_group_inputs[0]); - } - else { - return nullptr; + const DGroupInput &from_group_input = *from_group_inputs[0]; + if (is_multi_function_data_socket(from_group_input.bsocket())) { + return &common.network_map.lookup(from_group_input); } + return nullptr; } } diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index 6e7efb21850..c2c95f7c355 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -302,6 +302,17 @@ template class CustomMF_Constant : public MultiFunction { } }; +class CustomMF_DefaultOutput : public MultiFunction { + private: + uint output_amount_; + + public: + CustomMF_DefaultOutput(StringRef name, + Span input_types, + Span output_types); + void call(IndexMask mask, MFParams params, MFContext context) const override; +}; + } // namespace blender::fn #endif /* __FN_MULTI_FUNCTION_BUILDER_HH__ */ diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc index 889a2595aab..7797c19d563 100644 --- a/source/blender/functions/intern/multi_function_builder.cc +++ b/source/blender/functions/intern/multi_function_builder.cc @@ -87,4 +87,33 @@ void CustomMF_GenericConstantArray::call(IndexMask mask, } } +CustomMF_DefaultOutput::CustomMF_DefaultOutput(StringRef name, + Span input_types, + Span output_types) + : output_amount_(output_types.size()) +{ + MFSignatureBuilder signature = this->get_builder(name); + for (MFDataType data_type : input_types) { + signature.input("Input", data_type); + } + for (MFDataType data_type : output_types) { + signature.output("Output", data_type); + } +} +void CustomMF_DefaultOutput::call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const +{ + for (uint param_index : this->param_indices()) { + MFParamType param_type = this->param_type(param_index); + if (!param_type.is_output()) { + continue; + } + + if (param_type.data_type().is_single()) { + GMutableSpan span = params.uninitialized_single_output(param_index); + const CPPType &type = span.type(); + type.fill_uninitialized_indices(type.default_value(), span.buffer(), mask); + } + } +} + } // namespace blender::fn -- cgit v1.2.3