diff options
Diffstat (limited to 'source/blender/nodes/NOD_node_declaration.hh')
-rw-r--r-- | source/blender/nodes/NOD_node_declaration.hh | 295 |
1 files changed, 216 insertions, 79 deletions
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index 07d4e05cda8..113e8ffc93d 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -16,6 +16,7 @@ #pragma once +#include <functional> #include <type_traits> #include "BLI_string_ref.hh" @@ -23,6 +24,8 @@ #include "DNA_node_types.h" +struct bNode; + namespace blender::nodes { class NodeDeclarationBuilder; @@ -57,59 +60,15 @@ class OutputFieldDependency { Vector<int> linked_input_indices_; public: - static OutputFieldDependency ForFieldSource() - { - OutputFieldDependency field_dependency; - field_dependency.type_ = OutputSocketFieldType::FieldSource; - return field_dependency; - } - - static OutputFieldDependency ForDataSource() - { - OutputFieldDependency field_dependency; - field_dependency.type_ = OutputSocketFieldType::None; - return field_dependency; - } - - static OutputFieldDependency ForPartiallyDependentField(Vector<int> indices) - { - OutputFieldDependency field_dependency; - if (indices.is_empty()) { - field_dependency.type_ = OutputSocketFieldType::None; - } - else { - field_dependency.type_ = OutputSocketFieldType::PartiallyDependent; - field_dependency.linked_input_indices_ = std::move(indices); - } - return field_dependency; - } - - static OutputFieldDependency ForDependentField() - { - OutputFieldDependency field_dependency; - field_dependency.type_ = OutputSocketFieldType::DependentField; - return field_dependency; - } + static OutputFieldDependency ForFieldSource(); + static OutputFieldDependency ForDataSource(); + static OutputFieldDependency ForDependentField(); + static OutputFieldDependency ForPartiallyDependentField(Vector<int> indices); - OutputSocketFieldType field_type() const - { - return type_; - } + OutputSocketFieldType field_type() const; + Span<int> linked_input_indices() const; - Span<int> linked_input_indices() const - { - return linked_input_indices_; - } - - friend bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b) - { - return a.type_ == b.type_ && a.linked_input_indices_ == b.linked_input_indices_; - } - - friend bool operator!=(const OutputFieldDependency &a, const OutputFieldDependency &b) - { - return !(a == b); - } + friend bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b); }; /** @@ -118,16 +77,6 @@ class OutputFieldDependency { struct FieldInferencingInterface { Vector<InputSocketFieldType> inputs; Vector<OutputFieldDependency> outputs; - - friend bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b) - { - return a.inputs == b.inputs && a.outputs == b.outputs; - } - - friend bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b) - { - return !(a == b); - } }; /** @@ -138,27 +87,53 @@ class SocketDeclaration { std::string name_; std::string identifier_; std::string description_; + /** Defined by whether the socket is part of the node's input or + * output socket declaration list. Included here for convenience. */ + eNodeSocketInOut in_out_; bool hide_label_ = false; bool hide_value_ = false; + bool compact_ = false; bool is_multi_input_ = false; bool no_mute_links_ = false; + bool is_unavailable_ = false; + bool is_attribute_name_ = false; + bool is_default_link_socket_ = false; InputSocketFieldType input_field_type_ = InputSocketFieldType::None; OutputFieldDependency output_field_dependency_; + /** Utility method to make the socket available if there is a straightforward way to do so. */ + std::function<void(bNode &)> make_available_fn_; + friend NodeDeclarationBuilder; template<typename SocketDecl> friend class SocketDeclarationBuilder; public: virtual ~SocketDeclaration() = default; - virtual bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const = 0; + virtual bNodeSocket &build(bNodeTree &ntree, bNode &node) const = 0; virtual bool matches(const bNodeSocket &socket) const = 0; virtual bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const; + /** + * Determine if a new socket described by this declaration could have a valid connection + * the other socket. + */ + virtual bool can_connect(const bNodeSocket &socket) const = 0; + + /** + * Change the node such that the socket will become visible. The node type's update method + * should be called afterwards. + * \note Note that this is not necessarily implemented for all node types. + */ + void make_available(bNode &node) const; + StringRefNull name() const; StringRefNull description() const; StringRefNull identifier() const; + eNodeSocketInOut in_out() const; + bool is_attribute_name() const; + bool is_default_link_socket() const; InputSocketFieldType input_field_type() const; const OutputFieldDependency &output_field_dependency() const; @@ -211,12 +186,35 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder { decl_->description_ = std::move(value); return *(Self *)this; } + Self &no_muted_links(bool value = true) { decl_->no_mute_links_ = value; return *(Self *)this; } + /** + * Used for sockets that are always unavailable and should not be seen by the user. + * Ideally, no new calls to this method should be added over time. + */ + Self &unavailable(bool value = true) + { + decl_->is_unavailable_ = value; + return *(Self *)this; + } + + Self &is_attribute_name(bool value = true) + { + decl_->is_attribute_name_ = value; + return *(Self *)this; + } + + Self &is_default_link_socket(bool value = true) + { + decl_->is_default_link_socket_ = value; + return *(Self *)this; + } + /** The input socket allows passing in a field. */ Self &supports_field() { @@ -251,6 +249,19 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder { { decl_->output_field_dependency_ = OutputFieldDependency::ForPartiallyDependentField( std::move(input_dependencies)); + return *(Self *)this; + } + + /** + * Pass a function that sets properties on the node required to make the corresponding socket + * available, if it is not available on the default state of the node. The function is allowed to + * make other sockets unavailable, since it is meant to be called when the node is first added. + * The node type's update function is called afterwards. + */ + Self &make_available(std::function<void(bNode &)> fn) + { + decl_->make_available_fn_ = std::move(fn); + return *(Self *)this; } }; @@ -265,11 +276,11 @@ class NodeDeclaration { friend NodeDeclarationBuilder; public: - void build(bNodeTree &ntree, bNode &node) const; bool matches(const bNode &node) const; Span<SocketDeclarationPtr> inputs() const; Span<SocketDeclarationPtr> outputs() const; + Span<SocketDeclarationPtr> sockets(eNodeSocketInOut in_out) const; bool is_function_node() const { @@ -289,10 +300,13 @@ class NodeDeclarationBuilder { /** * All inputs support fields, and all outputs are fields if any of the inputs is a field. - * Calling field status definitions on each socket is unnecessary. + * Calling field status definitions on each socket is unnecessary. Must be called before adding + * any sockets. */ void is_function_node(bool value = true) { + BLI_assert_msg(declaration_.inputs().is_empty() && declaration_.outputs().is_empty(), + "is_function_node() must be called before any socket is created"); declaration_.is_function_node_ = value; } @@ -305,12 +319,88 @@ class NodeDeclarationBuilder { template<typename DeclType> typename DeclType::Builder &add_socket(StringRef name, StringRef identifier, - Vector<SocketDeclarationPtr> &r_decls); + eNodeSocketInOut in_out); }; -/* -------------------------------------------------------------------- - * SocketDeclaration inline methods. - */ +/* -------------------------------------------------------------------- */ +/** \name #OutputFieldDependency Inline Methods + * \{ */ + +inline OutputFieldDependency OutputFieldDependency::ForFieldSource() +{ + OutputFieldDependency field_dependency; + field_dependency.type_ = OutputSocketFieldType::FieldSource; + return field_dependency; +} + +inline OutputFieldDependency OutputFieldDependency::ForDataSource() +{ + OutputFieldDependency field_dependency; + field_dependency.type_ = OutputSocketFieldType::None; + return field_dependency; +} + +inline OutputFieldDependency OutputFieldDependency::ForDependentField() +{ + OutputFieldDependency field_dependency; + field_dependency.type_ = OutputSocketFieldType::DependentField; + return field_dependency; +} + +inline OutputFieldDependency OutputFieldDependency::ForPartiallyDependentField(Vector<int> indices) +{ + OutputFieldDependency field_dependency; + if (indices.is_empty()) { + field_dependency.type_ = OutputSocketFieldType::None; + } + else { + field_dependency.type_ = OutputSocketFieldType::PartiallyDependent; + field_dependency.linked_input_indices_ = std::move(indices); + } + return field_dependency; +} + +inline OutputSocketFieldType OutputFieldDependency::field_type() const +{ + return type_; +} + +inline Span<int> OutputFieldDependency::linked_input_indices() const +{ + return linked_input_indices_; +} + +inline bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b) +{ + return a.type_ == b.type_ && a.linked_input_indices_ == b.linked_input_indices_; +} + +inline bool operator!=(const OutputFieldDependency &a, const OutputFieldDependency &b) +{ + return !(a == b); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #FieldInferencingInterface Inline Methods + * \{ */ + +inline bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b) +{ + return a.inputs == b.inputs && a.outputs == b.outputs; +} + +inline bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b) +{ + return !(a == b); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #SocketDeclaration Inline Methods + * \{ */ inline StringRefNull SocketDeclaration::name() const { @@ -322,10 +412,26 @@ inline StringRefNull SocketDeclaration::identifier() const return identifier_; } +inline eNodeSocketInOut SocketDeclaration::in_out() const +{ + return in_out_; +} + inline StringRefNull SocketDeclaration::description() const { return description_; } + +inline bool SocketDeclaration::is_attribute_name() const +{ + return is_attribute_name_; +} + +inline bool SocketDeclaration::is_default_link_socket() const +{ + return is_default_link_socket_; +} + inline InputSocketFieldType SocketDeclaration::input_field_type() const { return input_field_type_; @@ -336,9 +442,18 @@ inline const OutputFieldDependency &SocketDeclaration::output_field_dependency() return output_field_dependency_; } -/* -------------------------------------------------------------------- - * NodeDeclarationBuilder inline methods. - */ +inline void SocketDeclaration::make_available(bNode &node) const +{ + if (make_available_fn_) { + make_available_fn_(node); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #NodeDeclarationBuilder Inline Methods + * \{ */ inline NodeDeclarationBuilder::NodeDeclarationBuilder(NodeDeclaration &declaration) : declaration_(declaration) @@ -349,36 +464,48 @@ template<typename DeclType> inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name, StringRef identifier) { - return this->add_socket<DeclType>(name, identifier, declaration_.inputs_); + return this->add_socket<DeclType>(name, identifier, SOCK_IN); } template<typename DeclType> inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef name, StringRef identifier) { - return this->add_socket<DeclType>(name, identifier, declaration_.outputs_); + return this->add_socket<DeclType>(name, identifier, SOCK_OUT); } template<typename DeclType> -inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket( - StringRef name, StringRef identifier, Vector<SocketDeclarationPtr> &r_decls) +inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef name, + StringRef identifier, + eNodeSocketInOut in_out) { static_assert(std::is_base_of_v<SocketDeclaration, DeclType>); using Builder = typename DeclType::Builder; + + Vector<SocketDeclarationPtr> &declarations = in_out == SOCK_IN ? declaration_.inputs_ : + declaration_.outputs_; + std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>(); std::unique_ptr<Builder> socket_decl_builder = std::make_unique<Builder>(); socket_decl_builder->decl_ = &*socket_decl; socket_decl->name_ = name; socket_decl->identifier_ = identifier.is_empty() ? name : identifier; - r_decls.append(std::move(socket_decl)); + socket_decl->in_out_ = in_out; + if (declaration_.is_function_node()) { + socket_decl->input_field_type_ = InputSocketFieldType::IsSupported; + socket_decl->output_field_dependency_ = OutputFieldDependency::ForDependentField(); + } + declarations.append(std::move(socket_decl)); Builder &socket_decl_builder_ref = *socket_decl_builder; builders_.append(std::move(socket_decl_builder)); return socket_decl_builder_ref; } -/* -------------------------------------------------------------------- - * NodeDeclaration inline methods. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #NodeDeclaration Inline Methods + * \{ */ inline Span<SocketDeclarationPtr> NodeDeclaration::inputs() const { @@ -390,4 +517,14 @@ inline Span<SocketDeclarationPtr> NodeDeclaration::outputs() const return outputs_; } +inline Span<SocketDeclarationPtr> NodeDeclaration::sockets(eNodeSocketInOut in_out) const +{ + if (in_out == SOCK_IN) { + return inputs_; + } + return outputs_; +} + +/** \} */ + } // namespace blender::nodes |