/* * 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. */ #pragma once /** \file * \ingroup nodes * * NodeTreeRef makes querying information about a bNodeTree more efficient. It is an immutable data * structure. It should not be used after anymore, after the underlying node tree changed. * * The following queries are supported efficiently: * - socket -> index of socket * - socket -> directly linked sockets * - socket -> linked sockets when skipping reroutes * - socket -> node * - socket/node -> rna pointer * - node -> inputs/outputs * - node -> tree * - tree -> all nodes * - tree -> all (input/output) sockets * - idname -> nodes * * Every socket has an id. The id-space is shared between input and output sockets. * When storing data per socket, it is often better to use the id as index into an array, instead * of a hash table. * * Every node has an id as well. The same rule regarding hash tables applies. * * There is an utility to export this data structure as graph in dot format. */ #include "BLI_array.hh" #include "BLI_linear_allocator.hh" #include "BLI_map.hh" #include "BLI_multi_value_map.hh" #include "BLI_string_ref.hh" #include "BLI_timeit.hh" #include "BLI_utility_mixins.hh" #include "BLI_vector.hh" #include "BKE_node.h" #include "DNA_node_types.h" #include "RNA_access.h" namespace blender::nodes { class SocketRef; class InputSocketRef; class OutputSocketRef; class NodeRef; class NodeTreeRef; class SocketRef : NonCopyable, NonMovable { protected: NodeRef *node_; bNodeSocket *bsocket_; bool is_input_; int id_; int index_; PointerRNA rna_; Vector linked_sockets_; Vector directly_linked_sockets_; friend NodeTreeRef; public: Span linked_sockets() const; Span directly_linked_sockets() const; bool is_linked() const; const NodeRef &node() const; const NodeTreeRef &tree() const; int id() const; int index() const; bool is_input() const; bool is_output() const; const SocketRef &as_base() const; const InputSocketRef &as_input() const; const OutputSocketRef &as_output() const; PointerRNA *rna() const; StringRefNull idname() const; StringRefNull name() const; bNodeSocket *bsocket() const; bNode *bnode() const; bNodeTree *btree() const; }; class InputSocketRef final : public SocketRef { public: Span linked_sockets() const; Span directly_linked_sockets() const; }; class OutputSocketRef final : public SocketRef { public: Span linked_sockets() const; Span directly_linked_sockets() const; }; class NodeRef : NonCopyable, NonMovable { private: NodeTreeRef *tree_; bNode *bnode_; PointerRNA rna_; int id_; Vector inputs_; Vector outputs_; friend NodeTreeRef; public: const NodeTreeRef &tree() const; Span inputs() const; Span outputs() const; const InputSocketRef &input(int index) const; const OutputSocketRef &output(int index) const; bNode *bnode() const; bNodeTree *btree() const; PointerRNA *rna() const; StringRefNull idname() const; StringRefNull name() const; int id() const; bool is_reroute_node() const; bool is_group_node() const; bool is_group_input_node() const; bool is_group_output_node() const; }; class NodeTreeRef : NonCopyable, NonMovable { private: LinearAllocator<> allocator_; bNodeTree *btree_; Vector nodes_by_id_; Vector sockets_by_id_; Vector input_sockets_; Vector output_sockets_; MultiValueMap nodes_by_type_; public: NodeTreeRef(bNodeTree *btree); ~NodeTreeRef(); Span nodes() const; Span nodes_by_type(StringRefNull idname) const; Span nodes_by_type(const bNodeType *nodetype) const; Span sockets() const; Span input_sockets() const; Span output_sockets() const; bNodeTree *btree() const; std::string to_dot() const; private: /* Utility functions used during construction. */ InputSocketRef &find_input_socket(Map &node_mapping, bNode *bnode, bNodeSocket *bsocket); OutputSocketRef &find_output_socket(Map &node_mapping, bNode *bnode, bNodeSocket *bsocket); void find_targets_skipping_reroutes(OutputSocketRef &socket_ref, Vector &r_targets); }; /* -------------------------------------------------------------------- * SocketRef inline methods. */ inline Span SocketRef::linked_sockets() const { return linked_sockets_; } inline Span SocketRef::directly_linked_sockets() const { return directly_linked_sockets_; } inline bool SocketRef::is_linked() const { return linked_sockets_.size() > 0; } inline const NodeRef &SocketRef::node() const { return *node_; } inline const NodeTreeRef &SocketRef::tree() const { return node_->tree(); } inline int SocketRef::id() const { return id_; } inline int SocketRef::index() const { return index_; } inline bool SocketRef::is_input() const { return is_input_; } inline bool SocketRef::is_output() const { return !is_input_; } inline const SocketRef &SocketRef::as_base() const { return *this; } inline const InputSocketRef &SocketRef::as_input() const { BLI_assert(this->is_input()); return static_cast(*this); } inline const OutputSocketRef &SocketRef::as_output() const { BLI_assert(this->is_output()); return static_cast(*this); } inline PointerRNA *SocketRef::rna() const { return const_cast(&rna_); } inline StringRefNull SocketRef::idname() const { return bsocket_->idname; } inline StringRefNull SocketRef::name() const { return bsocket_->name; } inline bNodeSocket *SocketRef::bsocket() const { return bsocket_; } inline bNode *SocketRef::bnode() const { return node_->bnode(); } inline bNodeTree *SocketRef::btree() const { return node_->btree(); } /* -------------------------------------------------------------------- * InputSocketRef inline methods. */ inline Span InputSocketRef::linked_sockets() const { return linked_sockets_.as_span().cast(); } inline Span InputSocketRef::directly_linked_sockets() const { return directly_linked_sockets_.as_span().cast(); } /* -------------------------------------------------------------------- * OutputSocketRef inline methods. */ inline Span OutputSocketRef::linked_sockets() const { return linked_sockets_.as_span().cast(); } inline Span OutputSocketRef::directly_linked_sockets() const { return directly_linked_sockets_.as_span().cast(); } /* -------------------------------------------------------------------- * NodeRef inline methods. */ inline const NodeTreeRef &NodeRef::tree() const { return *tree_; } inline Span NodeRef::inputs() const { return inputs_; } inline Span NodeRef::outputs() const { return outputs_; } inline const InputSocketRef &NodeRef::input(int index) const { return *inputs_[index]; } inline const OutputSocketRef &NodeRef::output(int index) const { return *outputs_[index]; } inline bNode *NodeRef::bnode() const { return bnode_; } inline bNodeTree *NodeRef::btree() const { return tree_->btree(); } inline PointerRNA *NodeRef::rna() const { return const_cast(&rna_); } inline StringRefNull NodeRef::idname() const { return bnode_->idname; } inline StringRefNull NodeRef::name() const { return bnode_->name; } inline int NodeRef::id() const { return id_; } inline bool NodeRef::is_reroute_node() const { return bnode_->type == NODE_REROUTE; } inline bool NodeRef::is_group_node() const { return bnode_->type == NODE_GROUP; } inline bool NodeRef::is_group_input_node() const { return bnode_->type == NODE_GROUP_INPUT; } inline bool NodeRef::is_group_output_node() const { return bnode_->type == NODE_GROUP_OUTPUT; } /* -------------------------------------------------------------------- * NodeRef inline methods. */ inline Span NodeTreeRef::nodes() const { return nodes_by_id_; } inline Span NodeTreeRef::nodes_by_type(StringRefNull idname) const { const bNodeType *nodetype = nodeTypeFind(idname.c_str()); return this->nodes_by_type(nodetype); } inline Span NodeTreeRef::nodes_by_type(const bNodeType *nodetype) const { return nodes_by_type_.lookup(nodetype); } inline Span NodeTreeRef::sockets() const { return sockets_by_id_; } inline Span NodeTreeRef::input_sockets() const { return input_sockets_; } inline Span NodeTreeRef::output_sockets() const { return output_sockets_; } inline bNodeTree *NodeTreeRef::btree() const { return btree_; } } // namespace blender::nodes