This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/nodes/NOD_node_tree_ref.hh

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

452 lines
10 KiB
C++
Raw Normal View History

/*
* 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<SocketRef *> linked_sockets_;
Vector<SocketRef *> directly_linked_sockets_;
friend NodeTreeRef;
public:
Span<const SocketRef *> linked_sockets() const;
Span<const SocketRef *> 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;
Geometry Nodes: initial scattering and geometry nodes This is the initial merge from the geometry-nodes branch. Nodes: * Attribute Math * Boolean * Edge Split * Float Compare * Object Info * Point Distribute * Point Instance * Random Attribute * Random Float * Subdivision Surface * Transform * Triangulate It includes the initial evaluation of geometry node groups in the Geometry Nodes modifier. Notes on the Generic attribute access API The API adds an indirection for attribute access. That has the following benefits: * Most code does not have to care about how an attribute is stored internally. This is mainly necessary, because we have to deal with "legacy" attributes such as vertex weights and attributes that are embedded into other structs such as vertex positions. * When reading from an attribute, we generally don't care what domain the attribute is stored on. So we want to abstract away the interpolation that that adapts attributes from one domain to another domain (this is not actually implemented yet). Other possible improvements for later iterations include: * Actually implement interpolation between domains. * Don't use inheritance for the different attribute types. A single class for read access and one for write access might be enough, because we know all the ways in which attributes are stored internally. We don't want more different internal structures in the future. On the contrary, ideally we can consolidate the different storage formats in the future to reduce the need for this indirection. * Remove the need for heap allocations when creating attribute accessors. It includes commits from: * Dalai Felinto * Hans Goudey * Jacques Lucke * Léo Depoix
2020-12-02 13:25:25 +01:00
StringRefNull identifier() const;
bNodeSocket *bsocket() const;
bNode *bnode() const;
bNodeTree *btree() const;
};
class InputSocketRef final : public SocketRef {
public:
Span<const OutputSocketRef *> linked_sockets() const;
Span<const OutputSocketRef *> directly_linked_sockets() const;
};
class OutputSocketRef final : public SocketRef {
public:
Span<const InputSocketRef *> linked_sockets() const;
Span<const InputSocketRef *> directly_linked_sockets() const;
};
class NodeRef : NonCopyable, NonMovable {
private:
NodeTreeRef *tree_;
bNode *bnode_;
PointerRNA rna_;
int id_;
Vector<InputSocketRef *> inputs_;
Vector<OutputSocketRef *> outputs_;
friend NodeTreeRef;
public:
const NodeTreeRef &tree() const;
Span<const InputSocketRef *> inputs() const;
Span<const OutputSocketRef *> 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;
bool is_muted() const;
};
class NodeTreeRef : NonCopyable, NonMovable {
private:
LinearAllocator<> allocator_;
bNodeTree *btree_;
Vector<NodeRef *> nodes_by_id_;
Vector<SocketRef *> sockets_by_id_;
Vector<InputSocketRef *> input_sockets_;
Vector<OutputSocketRef *> output_sockets_;
MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_;
public:
NodeTreeRef(bNodeTree *btree);
~NodeTreeRef();
Span<const NodeRef *> nodes() const;
Span<const NodeRef *> nodes_by_type(StringRefNull idname) const;
Span<const NodeRef *> nodes_by_type(const bNodeType *nodetype) const;
Span<const SocketRef *> sockets() const;
Span<const InputSocketRef *> input_sockets() const;
Span<const OutputSocketRef *> output_sockets() const;
Geometry Nodes: initial scattering and geometry nodes This is the initial merge from the geometry-nodes branch. Nodes: * Attribute Math * Boolean * Edge Split * Float Compare * Object Info * Point Distribute * Point Instance * Random Attribute * Random Float * Subdivision Surface * Transform * Triangulate It includes the initial evaluation of geometry node groups in the Geometry Nodes modifier. Notes on the Generic attribute access API The API adds an indirection for attribute access. That has the following benefits: * Most code does not have to care about how an attribute is stored internally. This is mainly necessary, because we have to deal with "legacy" attributes such as vertex weights and attributes that are embedded into other structs such as vertex positions. * When reading from an attribute, we generally don't care what domain the attribute is stored on. So we want to abstract away the interpolation that that adapts attributes from one domain to another domain (this is not actually implemented yet). Other possible improvements for later iterations include: * Actually implement interpolation between domains. * Don't use inheritance for the different attribute types. A single class for read access and one for write access might be enough, because we know all the ways in which attributes are stored internally. We don't want more different internal structures in the future. On the contrary, ideally we can consolidate the different storage formats in the future to reduce the need for this indirection. * Remove the need for heap allocations when creating attribute accessors. It includes commits from: * Dalai Felinto * Hans Goudey * Jacques Lucke * Léo Depoix
2020-12-02 13:25:25 +01:00
bool has_link_cycles() const;
bNodeTree *btree() const;
std::string to_dot() const;
private:
/* Utility functions used during construction. */
InputSocketRef &find_input_socket(Map<bNode *, NodeRef *> &node_mapping,
bNode *bnode,
bNodeSocket *bsocket);
OutputSocketRef &find_output_socket(Map<bNode *, NodeRef *> &node_mapping,
bNode *bnode,
bNodeSocket *bsocket);
void find_targets_skipping_reroutes(OutputSocketRef &socket_ref, Vector<SocketRef *> &r_targets);
};
/* --------------------------------------------------------------------
* SocketRef inline methods.
*/
inline Span<const SocketRef *> SocketRef::linked_sockets() const
{
return linked_sockets_;
}
inline Span<const SocketRef *> 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<const InputSocketRef &>(*this);
}
inline const OutputSocketRef &SocketRef::as_output() const
{
BLI_assert(this->is_output());
return static_cast<const OutputSocketRef &>(*this);
}
inline PointerRNA *SocketRef::rna() const
{
return const_cast<PointerRNA *>(&rna_);
}
inline StringRefNull SocketRef::idname() const
{
return bsocket_->idname;
}
inline StringRefNull SocketRef::name() const
{
return bsocket_->name;
}
Geometry Nodes: initial scattering and geometry nodes This is the initial merge from the geometry-nodes branch. Nodes: * Attribute Math * Boolean * Edge Split * Float Compare * Object Info * Point Distribute * Point Instance * Random Attribute * Random Float * Subdivision Surface * Transform * Triangulate It includes the initial evaluation of geometry node groups in the Geometry Nodes modifier. Notes on the Generic attribute access API The API adds an indirection for attribute access. That has the following benefits: * Most code does not have to care about how an attribute is stored internally. This is mainly necessary, because we have to deal with "legacy" attributes such as vertex weights and attributes that are embedded into other structs such as vertex positions. * When reading from an attribute, we generally don't care what domain the attribute is stored on. So we want to abstract away the interpolation that that adapts attributes from one domain to another domain (this is not actually implemented yet). Other possible improvements for later iterations include: * Actually implement interpolation between domains. * Don't use inheritance for the different attribute types. A single class for read access and one for write access might be enough, because we know all the ways in which attributes are stored internally. We don't want more different internal structures in the future. On the contrary, ideally we can consolidate the different storage formats in the future to reduce the need for this indirection. * Remove the need for heap allocations when creating attribute accessors. It includes commits from: * Dalai Felinto * Hans Goudey * Jacques Lucke * Léo Depoix
2020-12-02 13:25:25 +01:00
inline StringRefNull SocketRef::identifier() const
{
return bsocket_->identifier;
}
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<const OutputSocketRef *> InputSocketRef::linked_sockets() const
{
return linked_sockets_.as_span().cast<const OutputSocketRef *>();
}
inline Span<const OutputSocketRef *> InputSocketRef::directly_linked_sockets() const
{
return directly_linked_sockets_.as_span().cast<const OutputSocketRef *>();
}
/* --------------------------------------------------------------------
* OutputSocketRef inline methods.
*/
inline Span<const InputSocketRef *> OutputSocketRef::linked_sockets() const
{
return linked_sockets_.as_span().cast<const InputSocketRef *>();
}
inline Span<const InputSocketRef *> OutputSocketRef::directly_linked_sockets() const
{
return directly_linked_sockets_.as_span().cast<const InputSocketRef *>();
}
/* --------------------------------------------------------------------
* NodeRef inline methods.
*/
inline const NodeTreeRef &NodeRef::tree() const
{
return *tree_;
}
inline Span<const InputSocketRef *> NodeRef::inputs() const
{
return inputs_;
}
inline Span<const OutputSocketRef *> 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<PointerRNA *>(&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;
}
inline bool NodeRef::is_muted() const
{
return (bnode_->flag & NODE_MUTED) != 0;
}
/* --------------------------------------------------------------------
* NodeRef inline methods.
*/
inline Span<const NodeRef *> NodeTreeRef::nodes() const
{
return nodes_by_id_;
}
inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(StringRefNull idname) const
{
const bNodeType *nodetype = nodeTypeFind(idname.c_str());
return this->nodes_by_type(nodetype);
}
inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(const bNodeType *nodetype) const
{
return nodes_by_type_.lookup(nodetype);
}
inline Span<const SocketRef *> NodeTreeRef::sockets() const
{
return sockets_by_id_;
}
inline Span<const InputSocketRef *> NodeTreeRef::input_sockets() const
{
return input_sockets_;
}
inline Span<const OutputSocketRef *> NodeTreeRef::output_sockets() const
{
return output_sockets_;
}
inline bNodeTree *NodeTreeRef::btree() const
{
return btree_;
}
} // namespace blender::nodes