2020-06-09 17:08:41 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2020-07-17 11:36:59 +02:00
|
|
|
#include "NOD_derived_node_tree.hh"
|
2020-06-09 17:08:41 +02:00
|
|
|
|
2020-07-17 11:36:59 +02:00
|
|
|
namespace blender::nodes {
|
2020-06-09 17:08:41 +02:00
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
/* Construct a new derived node tree for a given root node tree. The generated derived node tree
|
|
|
|
* does not own the used node tree refs (so that those can be used by others as well). The caller
|
|
|
|
* has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
|
|
|
|
* derived node tree. */
|
|
|
|
DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs)
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
/* Construct all possible contexts immediately. This is significantly cheaper than inlining all
|
|
|
|
* node groups. If it still becomes a performance issue in the future, contexts could be
|
|
|
|
* constructed lazily when they are needed. */
|
|
|
|
root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs);
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context,
|
|
|
|
const NodeRef *parent_node,
|
|
|
|
bNodeTree &btree,
|
|
|
|
NodeTreeRefMap &node_tree_refs)
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-07 18:05:25 +01:00
|
|
|
DTreeContext &context = *allocator_.construct<DTreeContext>().release();
|
2021-03-06 16:51:06 +01:00
|
|
|
context.parent_context_ = parent_context;
|
|
|
|
context.parent_node_ = parent_node;
|
|
|
|
context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree);
|
|
|
|
used_node_tree_refs_.add(context.tree_);
|
|
|
|
|
|
|
|
for (const NodeRef *node : context.tree_->nodes()) {
|
|
|
|
if (node->is_group_node()) {
|
|
|
|
bNode *bnode = node->bnode();
|
|
|
|
bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id);
|
|
|
|
if (child_btree != nullptr) {
|
|
|
|
DTreeContext &child = this->construct_context_recursively(
|
|
|
|
&context, node, *child_btree, node_tree_refs);
|
|
|
|
context.children_.add_new(node, &child);
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
|
|
|
|
return context;
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
DerivedNodeTree::~DerivedNodeTree()
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
/* Has to be destructed manually, because the context info is allocated in a linear allocator. */
|
|
|
|
this->destruct_context_recursively(root_context_);
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
for (DTreeContext *child : context->children_.values()) {
|
|
|
|
this->destruct_context_recursively(child);
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
context->~DTreeContext();
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
/* Returns true if there are any cycles in the node tree. */
|
|
|
|
bool DerivedNodeTree::has_link_cycles() const
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
|
|
|
|
if (tree_ref->has_link_cycles()) {
|
|
|
|
return true;
|
|
|
|
}
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
return false;
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */
|
|
|
|
void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
this->foreach_node_in_context_recursive(*root_context_, callback);
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context,
|
|
|
|
FunctionRef<void(DNode)> callback) const
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
for (const NodeRef *node_ref : context.tree_->nodes()) {
|
|
|
|
callback(DNode(&context, node_ref));
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
for (const DTreeContext *child_context : context.children_.values()) {
|
|
|
|
this->foreach_node_in_context_recursive(*child_context, callback);
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
DOutputSocket DInputSocket::get_corresponding_group_node_output() const
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
BLI_assert(*this);
|
|
|
|
BLI_assert(socket_ref_->node().is_group_output_node());
|
|
|
|
BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1);
|
2020-06-09 17:08:41 +02:00
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
const DTreeContext *parent_context = context_->parent_context();
|
|
|
|
const NodeRef *parent_node = context_->parent_node();
|
|
|
|
BLI_assert(parent_context != nullptr);
|
|
|
|
BLI_assert(parent_node != nullptr);
|
2020-06-09 17:08:41 +02:00
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
const int socket_index = socket_ref_->index();
|
|
|
|
return {parent_context, &parent_node->output(socket_index)};
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() const
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
BLI_assert(*this);
|
|
|
|
BLI_assert(socket_ref_->node().is_group_node());
|
|
|
|
|
|
|
|
const DTreeContext *child_context = context_->child_context(socket_ref_->node());
|
|
|
|
BLI_assert(child_context != nullptr);
|
|
|
|
|
|
|
|
const NodeTreeRef &child_tree = child_context->tree();
|
|
|
|
Span<const NodeRef *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput");
|
|
|
|
const int socket_index = socket_ref_->index();
|
|
|
|
Vector<DOutputSocket> sockets;
|
|
|
|
for (const NodeRef *group_input_node : group_input_nodes) {
|
|
|
|
sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index)));
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
return sockets;
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
DInputSocket DOutputSocket::get_corresponding_group_node_input() const
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
BLI_assert(*this);
|
|
|
|
BLI_assert(socket_ref_->node().is_group_input_node());
|
|
|
|
BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1);
|
|
|
|
|
|
|
|
const DTreeContext *parent_context = context_->parent_context();
|
|
|
|
const NodeRef *parent_node = context_->parent_node();
|
|
|
|
BLI_assert(parent_context != nullptr);
|
|
|
|
BLI_assert(parent_node != nullptr);
|
|
|
|
|
|
|
|
const int socket_index = socket_ref_->index();
|
|
|
|
return {parent_context, &parent_node->input(socket_index)};
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
|
2020-11-27 19:38:14 +01:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
BLI_assert(*this);
|
|
|
|
BLI_assert(socket_ref_->node().is_group_node());
|
|
|
|
|
|
|
|
const DTreeContext *child_context = context_->child_context(socket_ref_->node());
|
|
|
|
BLI_assert(child_context != nullptr);
|
|
|
|
|
|
|
|
const NodeTreeRef &child_tree = child_context->tree();
|
|
|
|
Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput");
|
|
|
|
const int socket_index = socket_ref_->index();
|
|
|
|
for (const NodeRef *group_output_node : group_output_nodes) {
|
|
|
|
if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) {
|
|
|
|
return {child_context, &group_output_node->input(socket_index)};
|
2020-11-27 19:38:14 +01:00
|
|
|
}
|
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
return {};
|
2020-11-27 19:38:14 +01:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
/* Call the given callback for every "real" origin socket. "Real" means that reroutes, muted nodes
|
|
|
|
* and node groups are handled by this function. Origin sockets are ones where a node gets its
|
|
|
|
* inputs from. */
|
2021-03-19 21:10:55 +01:00
|
|
|
void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback) const
|
2020-11-27 19:38:14 +01:00
|
|
|
{
|
2021-03-06 16:51:06 +01:00
|
|
|
BLI_assert(*this);
|
2021-03-19 21:10:55 +01:00
|
|
|
for (const OutputSocketRef *linked_socket : socket_ref_->as_input().logically_linked_sockets()) {
|
2021-03-06 16:51:06 +01:00
|
|
|
const NodeRef &linked_node = linked_socket->node();
|
|
|
|
DOutputSocket linked_dsocket{context_, linked_socket};
|
|
|
|
|
2021-03-19 21:10:55 +01:00
|
|
|
if (linked_node.is_group_input_node()) {
|
2021-03-06 16:51:06 +01:00
|
|
|
if (context_->is_root()) {
|
|
|
|
/* This is a group input in the root node group. */
|
|
|
|
callback(linked_dsocket);
|
2020-11-27 19:38:14 +01:00
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
else {
|
|
|
|
DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input();
|
2021-03-19 21:10:55 +01:00
|
|
|
if (socket_in_parent_group->is_logically_linked()) {
|
2021-03-06 16:51:06 +01:00
|
|
|
/* Follow the links coming into the corresponding socket on the parent group node. */
|
|
|
|
socket_in_parent_group.foreach_origin_socket(callback);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* The corresponding input on the parent group node is not connected. Therefore, we use
|
|
|
|
* the value of that input socket directly. */
|
|
|
|
callback(socket_in_parent_group);
|
|
|
|
}
|
2020-11-27 19:38:14 +01:00
|
|
|
}
|
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
else if (linked_node.is_group_node()) {
|
|
|
|
DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket();
|
|
|
|
if (socket_in_group) {
|
2021-03-19 21:10:55 +01:00
|
|
|
if (socket_in_group->is_logically_linked()) {
|
2021-03-06 16:51:06 +01:00
|
|
|
/* Follow the links coming into the group output node of the child node group. */
|
|
|
|
socket_in_group.foreach_origin_socket(callback);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* The output of the child node group is not connected, so we have to get the value from
|
|
|
|
* that socket. */
|
|
|
|
callback(socket_in_group);
|
|
|
|
}
|
|
|
|
}
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
else {
|
|
|
|
/* The normal case: just use the value of a linked output socket. */
|
|
|
|
callback(linked_dsocket);
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
}
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 16:51:06 +01:00
|
|
|
/* Calls the given callback for every "real" target socket. "Real" means that reroutes, muted nodes
|
|
|
|
* and node groups are handled by this function. Target sockets are on the nodes that use the value
|
|
|
|
* from this socket. */
|
|
|
|
void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const
|
2020-06-09 17:08:41 +02:00
|
|
|
{
|
2021-03-19 21:10:55 +01:00
|
|
|
for (const InputSocketRef *linked_socket : socket_ref_->as_output().logically_linked_sockets()) {
|
2021-03-06 16:51:06 +01:00
|
|
|
const NodeRef &linked_node = linked_socket->node();
|
|
|
|
DInputSocket linked_dsocket{context_, linked_socket};
|
|
|
|
|
2021-03-19 21:10:55 +01:00
|
|
|
if (linked_node.is_group_output_node()) {
|
2021-03-06 16:51:06 +01:00
|
|
|
if (context_->is_root()) {
|
|
|
|
/* This is a group output in the root node group. */
|
|
|
|
callback(linked_dsocket);
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
else {
|
|
|
|
/* Follow the links going out of the group node in the parent node group. */
|
|
|
|
DOutputSocket socket_in_parent_group =
|
|
|
|
linked_dsocket.get_corresponding_group_node_output();
|
|
|
|
socket_in_parent_group.foreach_target_socket(callback);
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
}
|
2021-03-06 16:51:06 +01:00
|
|
|
else if (linked_node.is_group_node()) {
|
|
|
|
/* Follow the links within the nested node group. */
|
|
|
|
Vector<DOutputSocket> sockets_in_group =
|
|
|
|
linked_dsocket.get_corresponding_group_input_sockets();
|
|
|
|
for (DOutputSocket socket_in_group : sockets_in_group) {
|
|
|
|
socket_in_group.foreach_target_socket(callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* The normal case: just use the linked input socket as target. */
|
|
|
|
callback(linked_dsocket);
|
|
|
|
}
|
2020-06-09 17:08:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-17 11:36:59 +02:00
|
|
|
} // namespace blender::nodes
|