/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "NOD_node_declaration.hh" #include "NOD_socket_declarations.hh" #include "NOD_socket_declarations_geometry.hh" #include "BKE_geometry_fields.hh" #include "BKE_node.h" namespace blender::nodes { void build_node_declaration(const bNodeType &typeinfo, NodeDeclaration &r_declaration) { NodeDeclarationBuilder node_decl_builder{r_declaration}; typeinfo.declare(node_decl_builder); node_decl_builder.finalize(); } void build_node_declaration_dynamic(const bNodeTree &node_tree, const bNode &node, NodeDeclaration &r_declaration) { r_declaration.inputs.clear(); r_declaration.outputs.clear(); node.typeinfo->declare_dynamic(node_tree, node, r_declaration); } void NodeDeclarationBuilder::finalize() { if (is_function_node_) { for (std::unique_ptr &socket_builder : input_builders_) { SocketDeclaration &socket_decl = *socket_builder->declaration(); if (socket_decl.input_field_type != InputSocketFieldType::Implicit) { socket_decl.input_field_type = InputSocketFieldType::IsSupported; } } for (std::unique_ptr &socket_builder : output_builders_) { SocketDeclaration &socket_decl = *socket_builder->declaration(); socket_decl.output_field_dependency = OutputFieldDependency::ForDependentField(); socket_builder->reference_pass_all_ = true; } } Vector geometry_inputs; for (const int i : declaration_.inputs.index_range()) { if (dynamic_cast(declaration_.inputs[i].get())) { geometry_inputs.append(i); } } Vector geometry_outputs; for (const int i : declaration_.outputs.index_range()) { if (dynamic_cast(declaration_.outputs[i].get())) { geometry_outputs.append(i); } } for (std::unique_ptr &socket_builder : input_builders_) { if (socket_builder->field_on_all_) { aal::RelationsInNode &relations = this->get_anonymous_attribute_relations(); const int field_input = socket_builder->index_; for (const int geometry_input : geometry_inputs) { relations.eval_relations.append({field_input, geometry_input}); } } } for (std::unique_ptr &socket_builder : output_builders_) { if (socket_builder->field_on_all_) { aal::RelationsInNode &relations = this->get_anonymous_attribute_relations(); const int field_output = socket_builder->index_; for (const int geometry_output : geometry_outputs) { relations.available_relations.append({field_output, geometry_output}); } } if (socket_builder->reference_pass_all_) { aal::RelationsInNode &relations = this->get_anonymous_attribute_relations(); const int field_output = socket_builder->index_; for (const int input_i : declaration_.inputs.index_range()) { SocketDeclaration &input_socket_decl = *declaration_.inputs[input_i]; if (input_socket_decl.input_field_type != InputSocketFieldType::None) { relations.reference_relations.append({input_i, field_output}); } } } if (socket_builder->propagate_from_all_) { aal::RelationsInNode &relations = this->get_anonymous_attribute_relations(); const int geometry_output = socket_builder->index_; for (const int geometry_input : geometry_inputs) { relations.propagate_relations.append({geometry_input, geometry_output}); } } } } namespace anonymous_attribute_lifetime { bool operator==(const RelationsInNode &a, const RelationsInNode &b) { return a.propagate_relations == b.propagate_relations && a.reference_relations == b.reference_relations && a.eval_relations == b.eval_relations && a.available_relations == b.available_relations && a.available_on_none == b.available_on_none; } bool operator!=(const RelationsInNode &a, const RelationsInNode &b) { return !(a == b); } std::ostream &operator<<(std::ostream &stream, const RelationsInNode &relations) { stream << "Propagate Relations: " << relations.propagate_relations.size() << "\n"; for (const PropagateRelation &relation : relations.propagate_relations) { stream << " " << relation.from_geometry_input << " -> " << relation.to_geometry_output << "\n"; } stream << "Reference Relations: " << relations.reference_relations.size() << "\n"; for (const ReferenceRelation &relation : relations.reference_relations) { stream << " " << relation.from_field_input << " -> " << relation.to_field_output << "\n"; } stream << "Eval Relations: " << relations.eval_relations.size() << "\n"; for (const EvalRelation &relation : relations.eval_relations) { stream << " eval " << relation.field_input << " on " << relation.geometry_input << "\n"; } stream << "Available Relations: " << relations.available_relations.size() << "\n"; for (const AvailableRelation &relation : relations.available_relations) { stream << " " << relation.field_output << " available on " << relation.geometry_output << "\n"; } stream << "Available on None: " << relations.available_on_none.size() << "\n"; for (const int i : relations.available_on_none) { stream << " output " << i << " available on none\n"; } return stream; } } // namespace anonymous_attribute_lifetime bool NodeDeclaration::matches(const bNode &node) const { auto check_sockets = [&](ListBase sockets, Span socket_decls) { const int tot_sockets = BLI_listbase_count(&sockets); if (tot_sockets != socket_decls.size()) { return false; } int i; LISTBASE_FOREACH_INDEX (const bNodeSocket *, socket, &sockets, i) { const SocketDeclaration &socket_decl = *socket_decls[i]; if (!socket_decl.matches(*socket)) { return false; } } return true; }; if (!check_sockets(node.inputs, inputs)) { return false; } if (!check_sockets(node.outputs, outputs)) { return false; } return true; } bNodeSocket &SocketDeclaration::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const { /* By default just rebuild. */ BLI_assert(socket.in_out == this->in_out); UNUSED_VARS_NDEBUG(socket); return this->build(ntree, node); } void SocketDeclaration::set_common_flags(bNodeSocket &socket) const { SET_FLAG_FROM_TEST(socket.flag, compact, SOCK_COMPACT); SET_FLAG_FROM_TEST(socket.flag, hide_value, SOCK_HIDE_VALUE); SET_FLAG_FROM_TEST(socket.flag, hide_label, SOCK_HIDE_LABEL); SET_FLAG_FROM_TEST(socket.flag, is_multi_input, SOCK_MULTI_INPUT); SET_FLAG_FROM_TEST(socket.flag, no_mute_links, SOCK_NO_INTERNAL_LINK); SET_FLAG_FROM_TEST(socket.flag, is_unavailable, SOCK_UNAVAIL); } bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const { if (socket.name != this->name) { return false; } if (socket.identifier != this->identifier) { return false; } if (((socket.flag & SOCK_COMPACT) != 0) != this->compact) { return false; } if (((socket.flag & SOCK_HIDE_VALUE) != 0) != this->hide_value) { return false; } if (((socket.flag & SOCK_HIDE_LABEL) != 0) != this->hide_label) { return false; } if (((socket.flag & SOCK_MULTI_INPUT) != 0) != this->is_multi_input) { return false; } if (((socket.flag & SOCK_NO_INTERNAL_LINK) != 0) != this->no_mute_links) { return false; } if (((socket.flag & SOCK_UNAVAIL) != 0) != this->is_unavailable) { return false; } return true; } namespace implicit_field_inputs { void position(const bNode & /*node*/, void *r_value) { new (r_value) fn::ValueOrField(bke::AttributeFieldInput::Create("position")); } void normal(const bNode & /*node*/, void *r_value) { new (r_value) fn::ValueOrField(fn::Field(std::make_shared())); } void index(const bNode & /*node*/, void *r_value) { new (r_value) fn::ValueOrField(fn::Field(std::make_shared())); } void id_or_index(const bNode & /*node*/, void *r_value) { new (r_value) fn::ValueOrField(fn::Field(std::make_shared())); } } // namespace implicit_field_inputs } // namespace blender::nodes