Nodes: move NodeTreeRef functionality into node runtime data
The purpose of `NodeTreeRef` was to speed up various queries on a read-only `bNodeTree`. Not that we have runtime data in nodes and sockets, we can also store the result of some queries there. This has some benefits: * No need for a read-only separate node tree data structure which increased complexity. * Makes it easier to reuse cached queries in more parts of Blender that can benefit from it. A downside is that we loose some type safety that we got by having different types for input and output sockets, as well as internal and non-internal links. This patch also refactors `DerivedNodeTree` so that it does not use `NodeTreeRef` anymore, but uses `bNodeTree` directly instead. To provide a convenient API (that is also close to what `NodeTreeRef` has), a new approach is implemented: `bNodeTree`, `bNode`, `bNodeSocket` and `bNodeLink` now have C++ methods declared in `DNA_node_types.h` which are implemented in `BKE_node_runtime.hh`. To make this work, `makesdna` now skips c++ sections when parsing dna header files. No user visible changes are expected. Differential Revision: https://developer.blender.org/D15491
This commit is contained in:
@@ -3,9 +3,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "BLI_sys_types.h"
|
#include "BLI_multi_value_map.hh"
|
||||||
#include "BLI_utility_mixins.hh"
|
#include "BLI_utility_mixins.hh"
|
||||||
|
#include "BLI_vector.hh"
|
||||||
|
|
||||||
|
#include "DNA_node_types.h"
|
||||||
|
|
||||||
|
#include "BKE_node.h"
|
||||||
|
|
||||||
|
struct bNode;
|
||||||
|
struct bNodeSocket;
|
||||||
|
struct bNodeTree;
|
||||||
|
struct bNodeType;
|
||||||
|
|
||||||
namespace blender::nodes {
|
namespace blender::nodes {
|
||||||
struct FieldInferencingInterface;
|
struct FieldInferencingInterface;
|
||||||
@@ -36,6 +47,32 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
|
|||||||
|
|
||||||
/** Information about how inputs and outputs of the node group interact with fields. */
|
/** Information about how inputs and outputs of the node group interact with fields. */
|
||||||
std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface;
|
std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protects access to all topology cache variables below. This is necessary so that the cache can
|
||||||
|
* be updated on a const #bNodeTree.
|
||||||
|
*/
|
||||||
|
std::mutex topology_cache_mutex;
|
||||||
|
bool topology_cache_is_dirty = true;
|
||||||
|
bool topology_cache_exists = false;
|
||||||
|
/**
|
||||||
|
* Under some circumstances, it can be useful to use the cached data while editing the
|
||||||
|
* #bNodeTree. By default, this is protected against using an assert.
|
||||||
|
*/
|
||||||
|
mutable std::atomic<int> allow_use_dirty_topology_cache = 0;
|
||||||
|
|
||||||
|
/** Only valid when #topology_cache_is_dirty is false. */
|
||||||
|
Vector<bNode *> nodes;
|
||||||
|
Vector<bNodeLink *> links;
|
||||||
|
Vector<bNodeSocket *> sockets;
|
||||||
|
Vector<bNodeSocket *> input_sockets;
|
||||||
|
Vector<bNodeSocket *> output_sockets;
|
||||||
|
MultiValueMap<const bNodeType *, bNode *> nodes_by_type;
|
||||||
|
Vector<bNode *> toposort_left_to_right;
|
||||||
|
Vector<bNode *> toposort_right_to_left;
|
||||||
|
bool has_link_cycle = false;
|
||||||
|
bool has_undefined_nodes_or_sockets = false;
|
||||||
|
bNode *group_output_node = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,12 +84,24 @@ class bNodeSocketRuntime : NonCopyable, NonMovable {
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* References a socket declaration that is owned by `node->declaration`. This is only runtime
|
* References a socket declaration that is owned by `node->declaration`. This is only runtime
|
||||||
* data. It has to be updated when the node declaration changes.
|
* data. It has to be updated when the node declaration changes. Access can be allowed by using
|
||||||
|
* #AllowUsingOutdatedInfo.
|
||||||
*/
|
*/
|
||||||
const SocketDeclarationHandle *declaration = nullptr;
|
const SocketDeclarationHandle *declaration = nullptr;
|
||||||
|
|
||||||
/** #eNodeTreeChangedFlag. */
|
/** #eNodeTreeChangedFlag. */
|
||||||
uint32_t changed_flag = 0;
|
uint32_t changed_flag = 0;
|
||||||
|
|
||||||
|
/** Only valid when #topology_cache_is_dirty is false. */
|
||||||
|
Vector<bNodeLink *> directly_linked_links;
|
||||||
|
Vector<bNodeSocket *> directly_linked_sockets;
|
||||||
|
Vector<bNodeSocket *> logically_linked_sockets;
|
||||||
|
Vector<bNodeSocket *> logically_linked_skipped_sockets;
|
||||||
|
bNode *owner_node = nullptr;
|
||||||
|
bNodeSocket *internal_link_input = nullptr;
|
||||||
|
int index_in_node = -1;
|
||||||
|
int index_in_all_sockets = -1;
|
||||||
|
int index_in_inout_sockets = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,6 +133,392 @@ class bNodeRuntime : NonCopyable, NonMovable {
|
|||||||
|
|
||||||
/** #eNodeTreeChangedFlag. */
|
/** #eNodeTreeChangedFlag. */
|
||||||
uint32_t changed_flag = 0;
|
uint32_t changed_flag = 0;
|
||||||
|
|
||||||
|
/** Only valid if #topology_cache_is_dirty is false. */
|
||||||
|
Vector<bNodeSocket *> inputs;
|
||||||
|
Vector<bNodeSocket *> outputs;
|
||||||
|
Vector<bNodeLink *> internal_links;
|
||||||
|
Map<StringRefNull, bNodeSocket *> inputs_by_identifier;
|
||||||
|
Map<StringRefNull, bNodeSocket *> outputs_by_identifier;
|
||||||
|
int index_in_tree = -1;
|
||||||
|
bool has_linked_inputs = false;
|
||||||
|
bool has_linked_outputs = false;
|
||||||
|
bNodeTree *owner_tree = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace node_tree_runtime {
|
||||||
|
|
||||||
|
class AllowUsingOutdatedInfo : NonCopyable, NonMovable {
|
||||||
|
private:
|
||||||
|
const bNodeTree &tree_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AllowUsingOutdatedInfo(const bNodeTree &tree) : tree_(tree)
|
||||||
|
{
|
||||||
|
tree_.runtime->allow_use_dirty_topology_cache.fetch_add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AllowUsingOutdatedInfo()
|
||||||
|
{
|
||||||
|
tree_.runtime->allow_use_dirty_topology_cache.fetch_sub(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool topology_cache_is_available(const bNodeTree &tree)
|
||||||
|
{
|
||||||
|
if (!tree.runtime->topology_cache_exists) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tree.runtime->allow_use_dirty_topology_cache.load() > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !tree.runtime->topology_cache_is_dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool topology_cache_is_available(const bNode &node)
|
||||||
|
{
|
||||||
|
const bNodeTree *ntree = node.runtime->owner_tree;
|
||||||
|
if (ntree == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return topology_cache_is_available(*ntree);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool topology_cache_is_available(const bNodeSocket &socket)
|
||||||
|
{
|
||||||
|
const bNode *node = socket.runtime->owner_node;
|
||||||
|
if (node == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return topology_cache_is_available(*node);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace node_tree_runtime
|
||||||
|
|
||||||
} // namespace blender::bke
|
} // namespace blender::bke
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name #bNodeTree Inline Methods
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
inline blender::Span<bNode *> bNodeTree::nodes_by_type(const blender::StringRefNull type_idname)
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNode *> bNodeTree::nodes_by_type(
|
||||||
|
const blender::StringRefNull type_idname) const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNode *> bNodeTree::toposort_left_to_right() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->toposort_left_to_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNode *> bNodeTree::toposort_right_to_left() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->toposort_right_to_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNode *> bNodeTree::all_nodes() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<bNode *> bNodeTree::all_nodes()
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNodeTree::has_link_cycle() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->has_link_cycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNodeTree::has_undefined_nodes_or_sockets() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->has_undefined_nodes_or_sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNode *bNodeTree::group_output_node() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->group_output_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNodeSocket *> bNodeTree::all_input_sockets() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->input_sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<bNodeSocket *> bNodeTree::all_input_sockets()
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->input_sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNodeSocket *> bNodeTree::all_output_sockets() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->output_sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<bNodeSocket *> bNodeTree::all_output_sockets()
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->output_sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNodeSocket *> bNodeTree::all_sockets() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<bNodeSocket *> bNodeTree::all_sockets()
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name #bNode Inline Methods
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
inline blender::Span<bNodeSocket *> bNode::input_sockets()
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<bNodeSocket *> bNode::output_sockets()
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNodeSocket *> bNode::input_sockets() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNodeSocket *> bNode::output_sockets() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bNodeSocket &bNode::input_socket(int index)
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return *this->runtime->inputs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bNodeSocket &bNode::output_socket(int index)
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return *this->runtime->outputs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNodeSocket &bNode::input_socket(int index) const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return *this->runtime->inputs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNodeSocket &bNode::output_socket(int index) const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return *this->runtime->outputs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNodeSocket &bNode::input_by_identifier(blender::StringRef identifier) const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return *this->runtime->inputs_by_identifier.lookup_as(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNodeSocket &bNode::output_by_identifier(blender::StringRef identifier) const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return *this->runtime->outputs_by_identifier.lookup_as(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::StringRefNull bNode::label_or_name() const
|
||||||
|
{
|
||||||
|
if (this->label[0] == '\0') {
|
||||||
|
return this->name;
|
||||||
|
}
|
||||||
|
return this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNode::is_muted() const
|
||||||
|
{
|
||||||
|
return this->flag & NODE_MUTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNode::is_reroute() const
|
||||||
|
{
|
||||||
|
return this->type == NODE_REROUTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNode::is_frame() const
|
||||||
|
{
|
||||||
|
return this->type == NODE_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNode::is_group() const
|
||||||
|
{
|
||||||
|
return ELEM(this->type, NODE_GROUP, NODE_CUSTOM_GROUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNode::is_group_input() const
|
||||||
|
{
|
||||||
|
return this->type == NODE_GROUP_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNode::is_group_output() const
|
||||||
|
{
|
||||||
|
return this->type == NODE_GROUP_OUTPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNodeLink *> bNode::internal_links_span() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->internal_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const blender::nodes::NodeDeclaration *bNode::declaration() const
|
||||||
|
{
|
||||||
|
BLI_assert(this->runtime->declaration != nullptr);
|
||||||
|
return this->runtime->declaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name #bNodeLink Inline Methods
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
inline bool bNodeLink::is_muted() const
|
||||||
|
{
|
||||||
|
return this->flag & NODE_LINK_MUTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name #bNodeSocket Inline Methods
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
inline int bNodeSocket::index() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->index_in_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int bNodeSocket::index_in_tree() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->index_in_all_sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNodeSocket::is_available() const
|
||||||
|
{
|
||||||
|
return (this->flag & SOCK_UNAVAIL) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bNode &bNodeSocket::owner_node()
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return *this->runtime->owner_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNodeTree &bNodeSocket::owner_tree() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return *this->runtime->owner_node->runtime->owner_tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNodeSocket *> bNodeSocket::logically_linked_sockets() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->logically_linked_sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNodeLink *> bNodeSocket::directly_linked_links() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->directly_linked_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<bNodeLink *> bNodeSocket::directly_linked_links()
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->directly_linked_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blender::Span<const bNodeSocket *> bNodeSocket::directly_linked_sockets() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return this->runtime->directly_linked_sockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNodeSocket::is_directly_linked() const
|
||||||
|
{
|
||||||
|
return !this->directly_linked_links().is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNodeSocket::is_logically_linked() const
|
||||||
|
{
|
||||||
|
return !this->logically_linked_sockets().is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNodeSocket *bNodeSocket::internal_link_input() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
BLI_assert(this->in_out == SOCK_OUT);
|
||||||
|
return this->runtime->internal_link_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> const T *bNodeSocket::default_value_typed() const
|
||||||
|
{
|
||||||
|
return static_cast<const T *>(this->default_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNodeSocket::is_input() const
|
||||||
|
{
|
||||||
|
return this->in_out == SOCK_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNodeSocket::is_output() const
|
||||||
|
{
|
||||||
|
return this->in_out == SOCK_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool bNodeSocket::is_multi_input() const
|
||||||
|
{
|
||||||
|
return this->flag & SOCK_MULTI_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNode &bNodeSocket::owner_node() const
|
||||||
|
{
|
||||||
|
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||||
|
return *this->runtime->owner_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ set(SRC
|
|||||||
intern/multires_versioning.c
|
intern/multires_versioning.c
|
||||||
intern/nla.c
|
intern/nla.c
|
||||||
intern/node.cc
|
intern/node.cc
|
||||||
|
intern/node_runtime.cc
|
||||||
intern/node_tree_update.cc
|
intern/node_tree_update.cc
|
||||||
intern/object.cc
|
intern/object.cc
|
||||||
intern/object_deform.c
|
intern/object_deform.c
|
||||||
|
|||||||
@@ -72,7 +72,6 @@
|
|||||||
#include "NOD_function.h"
|
#include "NOD_function.h"
|
||||||
#include "NOD_geometry.h"
|
#include "NOD_geometry.h"
|
||||||
#include "NOD_node_declaration.hh"
|
#include "NOD_node_declaration.hh"
|
||||||
#include "NOD_node_tree_ref.hh"
|
|
||||||
#include "NOD_shader.h"
|
#include "NOD_shader.h"
|
||||||
#include "NOD_socket.h"
|
#include "NOD_socket.h"
|
||||||
#include "NOD_texture.h"
|
#include "NOD_texture.h"
|
||||||
@@ -104,7 +103,6 @@ using blender::nodes::NodeDeclaration;
|
|||||||
using blender::nodes::OutputFieldDependency;
|
using blender::nodes::OutputFieldDependency;
|
||||||
using blender::nodes::OutputSocketFieldType;
|
using blender::nodes::OutputSocketFieldType;
|
||||||
using blender::nodes::SocketDeclaration;
|
using blender::nodes::SocketDeclaration;
|
||||||
using namespace blender::nodes::node_tree_ref_types;
|
|
||||||
|
|
||||||
/* Fallback types for undefined tree, nodes, sockets */
|
/* Fallback types for undefined tree, nodes, sockets */
|
||||||
static bNodeTreeType NodeTreeTypeUndefined;
|
static bNodeTreeType NodeTreeTypeUndefined;
|
||||||
|
|||||||
403
source/blender/blenkernel/intern/node_runtime.cc
Normal file
403
source/blender/blenkernel/intern/node_runtime.cc
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include "BKE_node.h"
|
||||||
|
#include "BKE_node_runtime.hh"
|
||||||
|
|
||||||
|
#include "DNA_node_types.h"
|
||||||
|
|
||||||
|
#include "BLI_function_ref.hh"
|
||||||
|
#include "BLI_stack.hh"
|
||||||
|
#include "BLI_task.hh"
|
||||||
|
#include "BLI_timeit.hh"
|
||||||
|
|
||||||
|
namespace blender::bke::node_tree_runtime {
|
||||||
|
|
||||||
|
static void double_checked_lock(std::mutex &mutex, bool &data_is_dirty, FunctionRef<void()> fn)
|
||||||
|
{
|
||||||
|
if (!data_is_dirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::lock_guard lock{mutex};
|
||||||
|
if (!data_is_dirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fn();
|
||||||
|
data_is_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void double_checked_lock_with_task_isolation(std::mutex &mutex,
|
||||||
|
bool &data_is_dirty,
|
||||||
|
FunctionRef<void()> fn)
|
||||||
|
{
|
||||||
|
double_checked_lock(mutex, data_is_dirty, [&]() { threading::isolate_task(fn); });
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_node_vector(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
tree_runtime.nodes.clear();
|
||||||
|
tree_runtime.has_undefined_nodes_or_sockets = false;
|
||||||
|
LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
|
||||||
|
node->runtime->index_in_tree = tree_runtime.nodes.append_and_get_index(node);
|
||||||
|
node->runtime->owner_tree = const_cast<bNodeTree *>(&ntree);
|
||||||
|
tree_runtime.has_undefined_nodes_or_sockets |= node->typeinfo == &NodeTypeUndefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_link_vector(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
tree_runtime.links.clear();
|
||||||
|
LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
|
||||||
|
tree_runtime.links.append(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_internal_links(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
for (bNode *node : tree_runtime.nodes) {
|
||||||
|
node->runtime->internal_links.clear();
|
||||||
|
for (bNodeSocket *socket : node->runtime->outputs) {
|
||||||
|
socket->runtime->internal_link_input = nullptr;
|
||||||
|
}
|
||||||
|
LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
|
||||||
|
node->runtime->internal_links.append(link);
|
||||||
|
link->tosock->runtime->internal_link_input = link->fromsock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_socket_vectors_and_owner_node(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
tree_runtime.sockets.clear();
|
||||||
|
tree_runtime.input_sockets.clear();
|
||||||
|
tree_runtime.output_sockets.clear();
|
||||||
|
for (bNode *node : tree_runtime.nodes) {
|
||||||
|
bNodeRuntime &node_runtime = *node->runtime;
|
||||||
|
node_runtime.inputs.clear();
|
||||||
|
node_runtime.outputs.clear();
|
||||||
|
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
|
||||||
|
socket->runtime->index_in_node = node_runtime.inputs.append_and_get_index(socket);
|
||||||
|
socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket);
|
||||||
|
socket->runtime->index_in_inout_sockets = tree_runtime.input_sockets.append_and_get_index(
|
||||||
|
socket);
|
||||||
|
socket->runtime->owner_node = node;
|
||||||
|
tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined;
|
||||||
|
}
|
||||||
|
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
|
||||||
|
socket->runtime->index_in_node = node_runtime.outputs.append_and_get_index(socket);
|
||||||
|
socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket);
|
||||||
|
socket->runtime->index_in_inout_sockets = tree_runtime.output_sockets.append_and_get_index(
|
||||||
|
socket);
|
||||||
|
socket->runtime->owner_node = node;
|
||||||
|
tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_directly_linked_links_and_sockets(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
for (bNode *node : tree_runtime.nodes) {
|
||||||
|
for (bNodeSocket *socket : node->runtime->inputs) {
|
||||||
|
socket->runtime->directly_linked_links.clear();
|
||||||
|
socket->runtime->directly_linked_sockets.clear();
|
||||||
|
}
|
||||||
|
for (bNodeSocket *socket : node->runtime->outputs) {
|
||||||
|
socket->runtime->directly_linked_links.clear();
|
||||||
|
socket->runtime->directly_linked_sockets.clear();
|
||||||
|
}
|
||||||
|
node->runtime->has_linked_inputs = false;
|
||||||
|
node->runtime->has_linked_outputs = false;
|
||||||
|
}
|
||||||
|
for (bNodeLink *link : tree_runtime.links) {
|
||||||
|
link->fromsock->runtime->directly_linked_links.append(link);
|
||||||
|
link->fromsock->runtime->directly_linked_sockets.append(link->tosock);
|
||||||
|
link->tosock->runtime->directly_linked_links.append(link);
|
||||||
|
link->fromnode->runtime->has_linked_outputs = true;
|
||||||
|
link->tonode->runtime->has_linked_inputs = true;
|
||||||
|
}
|
||||||
|
for (bNodeSocket *socket : tree_runtime.input_sockets) {
|
||||||
|
if (socket->flag & SOCK_MULTI_INPUT) {
|
||||||
|
std::sort(socket->runtime->directly_linked_links.begin(),
|
||||||
|
socket->runtime->directly_linked_links.end(),
|
||||||
|
[&](const bNodeLink *a, const bNodeLink *b) {
|
||||||
|
return a->multi_input_socket_index > b->multi_input_socket_index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (bNodeSocket *socket : tree_runtime.input_sockets) {
|
||||||
|
for (bNodeLink *link : socket->runtime->directly_linked_links) {
|
||||||
|
/* Do this after sorting the input links. */
|
||||||
|
socket->runtime->directly_linked_sockets.append(link->fromsock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_logical_origins_for_socket_recursive(
|
||||||
|
bNodeSocket &input_socket,
|
||||||
|
bool only_follow_first_input_link,
|
||||||
|
Vector<bNodeSocket *, 16> &sockets_in_current_chain,
|
||||||
|
Vector<bNodeSocket *> &r_logical_origins,
|
||||||
|
Vector<bNodeSocket *> &r_skipped_origins)
|
||||||
|
{
|
||||||
|
if (sockets_in_current_chain.contains(&input_socket)) {
|
||||||
|
/* Protect against reroute recursions. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sockets_in_current_chain.append(&input_socket);
|
||||||
|
|
||||||
|
Span<bNodeLink *> links_to_check = input_socket.runtime->directly_linked_links;
|
||||||
|
if (only_follow_first_input_link) {
|
||||||
|
links_to_check = links_to_check.take_front(1);
|
||||||
|
}
|
||||||
|
for (bNodeLink *link : links_to_check) {
|
||||||
|
if (link->flag & NODE_LINK_MUTED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bNodeSocket &origin_socket = *link->fromsock;
|
||||||
|
bNode &origin_node = *link->fromnode;
|
||||||
|
if (!origin_socket.is_available()) {
|
||||||
|
/* Non available sockets are ignored. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (origin_node.type == NODE_REROUTE) {
|
||||||
|
bNodeSocket &reroute_input = *origin_node.runtime->inputs[0];
|
||||||
|
bNodeSocket &reroute_output = *origin_node.runtime->outputs[0];
|
||||||
|
r_skipped_origins.append(&reroute_input);
|
||||||
|
r_skipped_origins.append(&reroute_output);
|
||||||
|
find_logical_origins_for_socket_recursive(
|
||||||
|
reroute_input, false, sockets_in_current_chain, r_logical_origins, r_skipped_origins);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (origin_node.is_muted()) {
|
||||||
|
if (bNodeSocket *mute_input = origin_socket.runtime->internal_link_input) {
|
||||||
|
r_skipped_origins.append(&origin_socket);
|
||||||
|
r_skipped_origins.append(mute_input);
|
||||||
|
find_logical_origins_for_socket_recursive(
|
||||||
|
*mute_input, true, sockets_in_current_chain, r_logical_origins, r_skipped_origins);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
r_logical_origins.append(&origin_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
sockets_in_current_chain.pop_last();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_logical_origins(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) {
|
||||||
|
for (const int i : range) {
|
||||||
|
bNode &node = *tree_runtime.nodes[i];
|
||||||
|
for (bNodeSocket *socket : node.runtime->inputs) {
|
||||||
|
Vector<bNodeSocket *, 16> sockets_in_current_chain;
|
||||||
|
find_logical_origins_for_socket_recursive(
|
||||||
|
*socket,
|
||||||
|
false,
|
||||||
|
sockets_in_current_chain,
|
||||||
|
socket->runtime->logically_linked_sockets,
|
||||||
|
socket->runtime->logically_linked_skipped_sockets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_nodes_by_type(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
tree_runtime.nodes_by_type.clear();
|
||||||
|
for (bNode *node : tree_runtime.nodes) {
|
||||||
|
tree_runtime.nodes_by_type.add(node->typeinfo, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_sockets_by_identifier(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) {
|
||||||
|
for (bNode *node : tree_runtime.nodes.as_span().slice(range)) {
|
||||||
|
node->runtime->inputs_by_identifier.clear();
|
||||||
|
node->runtime->outputs_by_identifier.clear();
|
||||||
|
for (bNodeSocket *socket : node->runtime->inputs) {
|
||||||
|
node->runtime->inputs_by_identifier.add_new(socket->identifier, socket);
|
||||||
|
}
|
||||||
|
for (bNodeSocket *socket : node->runtime->outputs) {
|
||||||
|
node->runtime->outputs_by_identifier.add_new(socket->identifier, socket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ToposortDirection {
|
||||||
|
LeftToRight,
|
||||||
|
RightToLeft,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ToposortNodeState {
|
||||||
|
bool is_done = false;
|
||||||
|
bool is_in_stack = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void toposort_from_start_node(const ToposortDirection direction,
|
||||||
|
bNode &start_node,
|
||||||
|
MutableSpan<ToposortNodeState> node_states,
|
||||||
|
Vector<bNode *> &r_sorted_nodes,
|
||||||
|
bool &r_cycle_detected)
|
||||||
|
{
|
||||||
|
struct Item {
|
||||||
|
bNode *node;
|
||||||
|
int socket_index = 0;
|
||||||
|
int link_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Stack<Item, 64> nodes_to_check;
|
||||||
|
nodes_to_check.push({&start_node});
|
||||||
|
while (!nodes_to_check.is_empty()) {
|
||||||
|
Item &item = nodes_to_check.peek();
|
||||||
|
bNode &node = *item.node;
|
||||||
|
const Span<bNodeSocket *> sockets = (direction == ToposortDirection::LeftToRight) ?
|
||||||
|
node.runtime->inputs :
|
||||||
|
node.runtime->outputs;
|
||||||
|
while (true) {
|
||||||
|
if (item.socket_index == sockets.size()) {
|
||||||
|
/* All sockets have already been visited. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bNodeSocket &socket = *sockets[item.socket_index];
|
||||||
|
const Span<bNodeSocket *> linked_sockets = socket.runtime->directly_linked_sockets;
|
||||||
|
if (item.link_index == linked_sockets.size()) {
|
||||||
|
/* All links connected to this socket have already been visited. */
|
||||||
|
item.socket_index++;
|
||||||
|
item.link_index = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bNodeSocket &linked_socket = *linked_sockets[item.link_index];
|
||||||
|
bNode &linked_node = *linked_socket.runtime->owner_node;
|
||||||
|
ToposortNodeState &linked_node_state = node_states[linked_node.runtime->index_in_tree];
|
||||||
|
if (linked_node_state.is_done) {
|
||||||
|
/* The linked node has already been visited. */
|
||||||
|
item.link_index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (linked_node_state.is_in_stack) {
|
||||||
|
r_cycle_detected = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nodes_to_check.push({&linked_node});
|
||||||
|
linked_node_state.is_in_stack = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no other element has been pushed, the current node can be pushed to the sorted list. */
|
||||||
|
if (&item == &nodes_to_check.peek()) {
|
||||||
|
ToposortNodeState &node_state = node_states[node.runtime->index_in_tree];
|
||||||
|
node_state.is_done = true;
|
||||||
|
node_state.is_in_stack = false;
|
||||||
|
r_sorted_nodes.append(&node);
|
||||||
|
nodes_to_check.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_toposort(const bNodeTree &ntree,
|
||||||
|
const ToposortDirection direction,
|
||||||
|
Vector<bNode *> &r_sorted_nodes,
|
||||||
|
bool &r_cycle_detected)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
r_sorted_nodes.clear();
|
||||||
|
r_sorted_nodes.reserve(tree_runtime.nodes.size());
|
||||||
|
r_cycle_detected = false;
|
||||||
|
|
||||||
|
Array<ToposortNodeState> node_states(tree_runtime.nodes.size());
|
||||||
|
for (bNode *node : tree_runtime.nodes) {
|
||||||
|
if (node_states[node->runtime->index_in_tree].is_done) {
|
||||||
|
/* Ignore nodes that are done already. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((direction == ToposortDirection::LeftToRight) ? node->runtime->has_linked_outputs :
|
||||||
|
node->runtime->has_linked_inputs) {
|
||||||
|
/* Ignore non-start nodes. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r_sorted_nodes.size() < tree_runtime.nodes.size()) {
|
||||||
|
r_cycle_detected = true;
|
||||||
|
for (bNode *node : tree_runtime.nodes) {
|
||||||
|
if (node_states[node->runtime->index_in_tree].is_done) {
|
||||||
|
/* Ignore nodes that are done already. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Start toposort at this node which is somewhere in the middle of a loop. */
|
||||||
|
toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_assert(tree_runtime.nodes.size() == r_sorted_nodes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_group_output_node(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
const bNodeType *node_type = nodeTypeFind("NodeGroupOutput");
|
||||||
|
const Span<bNode *> group_output_nodes = tree_runtime.nodes_by_type.lookup(node_type);
|
||||||
|
if (group_output_nodes.is_empty()) {
|
||||||
|
tree_runtime.group_output_node = nullptr;
|
||||||
|
}
|
||||||
|
else if (group_output_nodes.size() == 1) {
|
||||||
|
tree_runtime.group_output_node = group_output_nodes[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (bNode *group_output : group_output_nodes) {
|
||||||
|
if (group_output->flag & NODE_DO_OUTPUT) {
|
||||||
|
tree_runtime.group_output_node = group_output;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ensure_topology_cache(const bNodeTree &ntree)
|
||||||
|
{
|
||||||
|
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
|
||||||
|
double_checked_lock_with_task_isolation(
|
||||||
|
tree_runtime.topology_cache_mutex, tree_runtime.topology_cache_is_dirty, [&]() {
|
||||||
|
update_node_vector(ntree);
|
||||||
|
update_link_vector(ntree);
|
||||||
|
update_socket_vectors_and_owner_node(ntree);
|
||||||
|
update_internal_links(ntree);
|
||||||
|
update_directly_linked_links_and_sockets(ntree);
|
||||||
|
threading::parallel_invoke([&]() { update_logical_origins(ntree); },
|
||||||
|
[&]() { update_nodes_by_type(ntree); },
|
||||||
|
[&]() { update_sockets_by_identifier(ntree); },
|
||||||
|
[&]() {
|
||||||
|
update_toposort(ntree,
|
||||||
|
ToposortDirection::LeftToRight,
|
||||||
|
tree_runtime.toposort_left_to_right,
|
||||||
|
tree_runtime.has_link_cycle);
|
||||||
|
},
|
||||||
|
[&]() {
|
||||||
|
bool dummy;
|
||||||
|
update_toposort(ntree,
|
||||||
|
ToposortDirection::RightToLeft,
|
||||||
|
tree_runtime.toposort_right_to_left,
|
||||||
|
dummy);
|
||||||
|
});
|
||||||
|
update_group_output_node(ntree);
|
||||||
|
tree_runtime.topology_cache_exists = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender::bke::node_tree_runtime
|
||||||
|
|
||||||
|
void bNodeTree::ensure_topology_cache() const
|
||||||
|
{
|
||||||
|
blender::bke::node_tree_runtime::ensure_topology_cache(*this);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -137,6 +137,11 @@ template<typename Key, typename Value> class MultiValueMap {
|
|||||||
{
|
{
|
||||||
return map_.values();
|
return map_.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
map_.clear();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender
|
} // namespace blender
|
||||||
|
|||||||
@@ -104,9 +104,6 @@ class Evaluator {
|
|||||||
Context &context_;
|
Context &context_;
|
||||||
/* A reference to the compositor node tree. */
|
/* A reference to the compositor node tree. */
|
||||||
bNodeTree &node_tree_;
|
bNodeTree &node_tree_;
|
||||||
/* The derived and reference node trees representing the compositor node tree. Those are
|
|
||||||
* initialized when the node tree is compiled and freed when the evaluator resets. */
|
|
||||||
NodeTreeRefMap node_tree_reference_map_;
|
|
||||||
std::unique_ptr<DerivedNodeTree> derived_node_tree_;
|
std::unique_ptr<DerivedNodeTree> derived_node_tree_;
|
||||||
/* The compiled operations stream. This contains ordered pointers to the operations that were
|
/* The compiled operations stream. This contains ordered pointers to the operations that were
|
||||||
* compiled. This is initialized when the node tree is compiled and freed when the evaluator
|
* compiled. This is initialized when the node tree is compiled and freed when the evaluator
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ DSocket get_input_origin_socket(DInputSocket input);
|
|||||||
DOutputSocket get_output_linked_to_input(DInputSocket input);
|
DOutputSocket get_output_linked_to_input(DInputSocket input);
|
||||||
|
|
||||||
/* Get the result type that corresponds to the type of the given socket. */
|
/* Get the result type that corresponds to the type of the given socket. */
|
||||||
ResultType get_node_socket_result_type(const SocketRef *socket);
|
ResultType get_node_socket_result_type(const bNodeSocket *socket);
|
||||||
|
|
||||||
/* Returns true if any of the nodes linked to the given output satisfies the given condition, and
|
/* Returns true if any of the nodes linked to the given output satisfies the given condition, and
|
||||||
* false otherwise. */
|
* false otherwise. */
|
||||||
@@ -46,7 +46,7 @@ bool is_shader_node(DNode node);
|
|||||||
bool is_node_supported(DNode node);
|
bool is_node_supported(DNode node);
|
||||||
|
|
||||||
/* Get the input descriptor of the given input socket. */
|
/* Get the input descriptor of the given input socket. */
|
||||||
InputDescriptor input_descriptor_from_input_socket(const InputSocketRef *socket);
|
InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket);
|
||||||
|
|
||||||
/* Dispatch the given compute shader in a 2D compute space such that the number of threads in both
|
/* Dispatch the given compute shader in a 2D compute space such that the number of threads in both
|
||||||
* dimensions is as small as possible but at least covers the entirety of threads_range assuming
|
* dimensions is as small as possible but at least covers the entirety of threads_range assuming
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Result &CompileState::get_result_from_output_socket(DOutputSocket output)
|
|||||||
* reference to the result from that operation using the output identifier. */
|
* reference to the result from that operation using the output identifier. */
|
||||||
if (node_operations_.contains(output.node())) {
|
if (node_operations_.contains(output.node())) {
|
||||||
NodeOperation *operation = node_operations_.lookup(output.node());
|
NodeOperation *operation = node_operations_.lookup(output.node());
|
||||||
return operation->get_result(output->identifier());
|
return operation->get_result(output->identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, the output belongs to a node that was compiled into a shader operation, so
|
/* Otherwise, the output belongs to a node that was compiled into a shader operation, so
|
||||||
@@ -113,17 +113,17 @@ Domain CompileState::compute_shader_node_domain(DNode node)
|
|||||||
|
|
||||||
/* Go over the inputs and find the domain of the non single value input with the highest domain
|
/* Go over the inputs and find the domain of the non single value input with the highest domain
|
||||||
* priority. */
|
* priority. */
|
||||||
for (const InputSocketRef *input_ref : node->inputs()) {
|
for (const bNodeSocket *input : node->input_sockets()) {
|
||||||
const DInputSocket input{node.context(), input_ref};
|
const DInputSocket dinput{node.context(), input};
|
||||||
|
|
||||||
/* Get the output linked to the input. If it is null, that means the input is unlinked, so skip
|
/* Get the output linked to the input. If it is null, that means the input is unlinked, so skip
|
||||||
* it. */
|
* it. */
|
||||||
const DOutputSocket output = get_output_linked_to_input(input);
|
const DOutputSocket output = get_output_linked_to_input(dinput);
|
||||||
if (!output) {
|
if (!output) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_ref);
|
const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input);
|
||||||
|
|
||||||
/* If the output belongs to a node that is part of the shader compile unit, then the domain of
|
/* If the output belongs to a node that is part of the shader compile unit, then the domain of
|
||||||
* the input is the domain of the compile unit itself. */
|
* the input is the domain of the compile unit itself. */
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ void Evaluator::reset()
|
|||||||
{
|
{
|
||||||
operations_stream_.clear();
|
operations_stream_.clear();
|
||||||
derived_node_tree_.reset();
|
derived_node_tree_.reset();
|
||||||
node_tree_reference_map_.clear();
|
|
||||||
|
|
||||||
is_compiled_ = false;
|
is_compiled_ = false;
|
||||||
}
|
}
|
||||||
@@ -67,7 +66,7 @@ bool Evaluator::validate_node_tree()
|
|||||||
|
|
||||||
void Evaluator::compile_and_evaluate()
|
void Evaluator::compile_and_evaluate()
|
||||||
{
|
{
|
||||||
derived_node_tree_ = std::make_unique<DerivedNodeTree>(node_tree_, node_tree_reference_map_);
|
derived_node_tree_ = std::make_unique<DerivedNodeTree>(node_tree_);
|
||||||
|
|
||||||
if (!validate_node_tree()) {
|
if (!validate_node_tree()) {
|
||||||
return;
|
return;
|
||||||
@@ -93,7 +92,7 @@ void Evaluator::compile_and_evaluate()
|
|||||||
|
|
||||||
void Evaluator::compile_and_evaluate_node(DNode node, CompileState &compile_state)
|
void Evaluator::compile_and_evaluate_node(DNode node, CompileState &compile_state)
|
||||||
{
|
{
|
||||||
NodeOperation *operation = node->typeinfo()->get_compositor_operation(context_, node);
|
NodeOperation *operation = node->typeinfo->get_compositor_operation(context_, node);
|
||||||
|
|
||||||
compile_state.map_node_to_node_operation(node, operation);
|
compile_state.map_node_to_node_operation(node, operation);
|
||||||
|
|
||||||
@@ -113,16 +112,16 @@ void Evaluator::map_node_operation_inputs_to_their_results(DNode node,
|
|||||||
NodeOperation *operation,
|
NodeOperation *operation,
|
||||||
CompileState &compile_state)
|
CompileState &compile_state)
|
||||||
{
|
{
|
||||||
for (const InputSocketRef *input_ref : node->inputs()) {
|
for (const bNodeSocket *input : node->input_sockets()) {
|
||||||
const DInputSocket input{node.context(), input_ref};
|
const DInputSocket dinput{node.context(), input};
|
||||||
|
|
||||||
DSocket origin = get_input_origin_socket(input);
|
DSocket dorigin = get_input_origin_socket(dinput);
|
||||||
|
|
||||||
/* The origin socket is an output, which means the input is linked. So map the input to the
|
/* The origin socket is an output, which means the input is linked. So map the input to the
|
||||||
* result we get from the output. */
|
* result we get from the output. */
|
||||||
if (origin->is_output()) {
|
if (dorigin->is_output()) {
|
||||||
Result &result = compile_state.get_result_from_output_socket(DOutputSocket(origin));
|
Result &result = compile_state.get_result_from_output_socket(DOutputSocket(dorigin));
|
||||||
operation->map_input_to_result(input->identifier(), &result);
|
operation->map_input_to_result(input->identifier, &result);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,8 +129,8 @@ void Evaluator::map_node_operation_inputs_to_their_results(DNode node,
|
|||||||
* origin is the input socket itself or the input is connected to an unlinked input of a group
|
* origin is the input socket itself or the input is connected to an unlinked input of a group
|
||||||
* input node and the origin is the input of the group input node. So map the input to the
|
* input node and the origin is the input of the group input node. So map the input to the
|
||||||
* result of a newly created Input Single Value Operation. */
|
* result of a newly created Input Single Value Operation. */
|
||||||
auto *input_operation = new InputSingleValueOperation(context_, DInputSocket(origin));
|
auto *input_operation = new InputSingleValueOperation(context_, DInputSocket(dorigin));
|
||||||
operation->map_input_to_result(input->identifier(), &input_operation->get_result());
|
operation->map_input_to_result(input->identifier, &input_operation->get_result());
|
||||||
|
|
||||||
operations_stream_.append(std::unique_ptr<InputSingleValueOperation>(input_operation));
|
operations_stream_.append(std::unique_ptr<InputSingleValueOperation>(input_operation));
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const StringRef InputSingleValueOperation::output_identifier_ = StringRef("Outpu
|
|||||||
InputSingleValueOperation::InputSingleValueOperation(Context &context, DInputSocket input_socket)
|
InputSingleValueOperation::InputSingleValueOperation(Context &context, DInputSocket input_socket)
|
||||||
: Operation(context), input_socket_(input_socket)
|
: Operation(context), input_socket_(input_socket)
|
||||||
{
|
{
|
||||||
const ResultType result_type = get_node_socket_result_type(input_socket_.socket_ref());
|
const ResultType result_type = get_node_socket_result_type(input_socket_.bsocket());
|
||||||
Result result = Result(result_type, texture_pool());
|
Result result = Result(result_type, texture_pool());
|
||||||
|
|
||||||
/* The result of an input single value operation is guaranteed to have a single user. */
|
/* The result of an input single value operation is guaranteed to have a single user. */
|
||||||
@@ -29,17 +29,19 @@ void InputSingleValueOperation::execute()
|
|||||||
Result &result = get_result();
|
Result &result = get_result();
|
||||||
result.allocate_single_value();
|
result.allocate_single_value();
|
||||||
|
|
||||||
|
const bNodeSocket *bsocket = input_socket_.bsocket();
|
||||||
|
|
||||||
/* Set the value of the result to the default value of the input socket. */
|
/* Set the value of the result to the default value of the input socket. */
|
||||||
switch (result.type()) {
|
switch (result.type()) {
|
||||||
case ResultType::Float:
|
case ResultType::Float:
|
||||||
result.set_float_value(input_socket_->default_value<bNodeSocketValueFloat>()->value);
|
result.set_float_value(bsocket->default_value_typed<bNodeSocketValueFloat>()->value);
|
||||||
break;
|
break;
|
||||||
case ResultType::Vector:
|
case ResultType::Vector:
|
||||||
result.set_vector_value(
|
result.set_vector_value(
|
||||||
float3(input_socket_->default_value<bNodeSocketValueVector>()->value));
|
float3(bsocket->default_value_typed<bNodeSocketValueVector>()->value));
|
||||||
break;
|
break;
|
||||||
case ResultType::Color:
|
case ResultType::Color:
|
||||||
result.set_color_value(float4(input_socket_->default_value<bNodeSocketValueRGBA>()->value));
|
result.set_color_value(float4(bsocket->default_value_typed<bNodeSocketValueRGBA>()->value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,27 +25,27 @@ using namespace nodes::derived_node_tree_types;
|
|||||||
|
|
||||||
NodeOperation::NodeOperation(Context &context, DNode node) : Operation(context), node_(node)
|
NodeOperation::NodeOperation(Context &context, DNode node) : Operation(context), node_(node)
|
||||||
{
|
{
|
||||||
for (const OutputSocketRef *output : node->outputs()) {
|
for (const bNodeSocket *output : node->output_sockets()) {
|
||||||
const ResultType result_type = get_node_socket_result_type(output);
|
const ResultType result_type = get_node_socket_result_type(output);
|
||||||
const Result result = Result(result_type, texture_pool());
|
const Result result = Result(result_type, texture_pool());
|
||||||
populate_result(output->identifier(), result);
|
populate_result(output->identifier, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const InputSocketRef *input : node->inputs()) {
|
for (const bNodeSocket *input : node->input_sockets()) {
|
||||||
const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input);
|
const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input);
|
||||||
declare_input_descriptor(input->identifier(), input_descriptor);
|
declare_input_descriptor(input->identifier, input_descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeOperation::compute_results_reference_counts(const Schedule &schedule)
|
void NodeOperation::compute_results_reference_counts(const Schedule &schedule)
|
||||||
{
|
{
|
||||||
for (const OutputSocketRef *output_ref : node()->outputs()) {
|
for (const bNodeSocket *output : this->node()->output_sockets()) {
|
||||||
const DOutputSocket output{node().context(), output_ref};
|
const DOutputSocket doutput{node().context(), output};
|
||||||
|
|
||||||
const int reference_count = number_of_inputs_linked_to_output_conditioned(
|
const int reference_count = number_of_inputs_linked_to_output_conditioned(
|
||||||
output, [&](DInputSocket input) { return schedule.contains(input.node()); });
|
doutput, [&](DInputSocket input) { return schedule.contains(input.node()); });
|
||||||
|
|
||||||
get_result(output->identifier()).set_initial_reference_count(reference_count);
|
get_result(doutput->identifier).set_initial_reference_count(reference_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ const DNode &NodeOperation::node() const
|
|||||||
|
|
||||||
const bNode &NodeOperation::bnode() const
|
const bNode &NodeOperation::bnode() const
|
||||||
{
|
{
|
||||||
return *node_->bnode();
|
return *node_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NodeOperation::should_compute_output(StringRef identifier)
|
bool NodeOperation::should_compute_output(StringRef identifier)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "NOD_derived_node_tree.hh"
|
#include "NOD_derived_node_tree.hh"
|
||||||
|
|
||||||
|
#include "BKE_node_runtime.hh"
|
||||||
|
|
||||||
#include "COM_scheduler.hh"
|
#include "COM_scheduler.hh"
|
||||||
#include "COM_utilities.hh"
|
#include "COM_utilities.hh"
|
||||||
|
|
||||||
@@ -21,22 +23,22 @@ using namespace nodes::derived_node_tree_types;
|
|||||||
* node will be returned. */
|
* node will be returned. */
|
||||||
static DNode compute_output_node(DerivedNodeTree &tree)
|
static DNode compute_output_node(DerivedNodeTree &tree)
|
||||||
{
|
{
|
||||||
const NodeTreeRef &root_tree = tree.root_context().tree();
|
const bNodeTree &root_tree = tree.root_context().btree();
|
||||||
|
|
||||||
for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeComposite")) {
|
for (const bNode *node : root_tree.nodes_by_type("CompositorNodeComposite")) {
|
||||||
if (node->bnode()->flag & NODE_DO_OUTPUT) {
|
if (node->flag & NODE_DO_OUTPUT) {
|
||||||
return DNode(&tree.root_context(), node);
|
return DNode(&tree.root_context(), node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeViewer")) {
|
for (const bNode *node : root_tree.nodes_by_type("CompositorNodeViewer")) {
|
||||||
if (node->bnode()->flag & NODE_DO_OUTPUT) {
|
if (node->flag & NODE_DO_OUTPUT) {
|
||||||
return DNode(&tree.root_context(), node);
|
return DNode(&tree.root_context(), node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) {
|
for (const bNode *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) {
|
||||||
if (node->bnode()->flag & NODE_DO_OUTPUT) {
|
if (node->flag & NODE_DO_OUTPUT) {
|
||||||
return DNode(&tree.root_context(), node);
|
return DNode(&tree.root_context(), node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,25 +122,25 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node)
|
|||||||
/* Go over the node dependencies connected to the inputs of the node and push them to the node
|
/* Go over the node dependencies connected to the inputs of the node and push them to the node
|
||||||
* stack if they were not computed already. */
|
* stack if they were not computed already. */
|
||||||
Set<DNode> pushed_nodes;
|
Set<DNode> pushed_nodes;
|
||||||
for (const InputSocketRef *input_ref : node->inputs()) {
|
for (const bNodeSocket *input : node->input_sockets()) {
|
||||||
const DInputSocket input{node.context(), input_ref};
|
const DInputSocket dinput{node.context(), input};
|
||||||
|
|
||||||
/* Get the output linked to the input. If it is null, that means the input is unlinked and
|
/* Get the output linked to the input. If it is null, that means the input is unlinked and
|
||||||
* has no dependency node. */
|
* has no dependency node. */
|
||||||
const DOutputSocket output = get_output_linked_to_input(input);
|
const DOutputSocket doutput = get_output_linked_to_input(dinput);
|
||||||
if (!output) {
|
if (!doutput) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The node dependency was already computed or pushed before, so skip it. */
|
/* The node dependency was already computed or pushed before, so skip it. */
|
||||||
if (needed_buffers.contains(output.node()) || pushed_nodes.contains(output.node())) {
|
if (needed_buffers.contains(doutput.node()) || pushed_nodes.contains(doutput.node())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The output node needs to be computed, push the node dependency to the node stack and
|
/* The output node needs to be computed, push the node dependency to the node stack and
|
||||||
* indicate that it was pushed. */
|
* indicate that it was pushed. */
|
||||||
node_stack.push(output.node());
|
node_stack.push(doutput.node());
|
||||||
pushed_nodes.add_new(output.node());
|
pushed_nodes.add_new(doutput.node());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If any of the node dependencies were pushed, that means that not all of them were computed
|
/* If any of the node dependencies were pushed, that means that not all of them were computed
|
||||||
@@ -154,26 +156,26 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node)
|
|||||||
* buffers needed to compute the most demanding of the node dependencies. */
|
* buffers needed to compute the most demanding of the node dependencies. */
|
||||||
int number_of_input_buffers = 0;
|
int number_of_input_buffers = 0;
|
||||||
int buffers_needed_by_dependencies = 0;
|
int buffers_needed_by_dependencies = 0;
|
||||||
for (const InputSocketRef *input_ref : node->inputs()) {
|
for (const bNodeSocket *input : node->input_sockets()) {
|
||||||
const DInputSocket input{node.context(), input_ref};
|
const DInputSocket dinput{node.context(), input};
|
||||||
|
|
||||||
/* Get the output linked to the input. If it is null, that means the input is unlinked.
|
/* Get the output linked to the input. If it is null, that means the input is unlinked.
|
||||||
* Unlinked inputs do not take a buffer, so skip those inputs. */
|
* Unlinked inputs do not take a buffer, so skip those inputs. */
|
||||||
const DOutputSocket output = get_output_linked_to_input(input);
|
const DOutputSocket doutput = get_output_linked_to_input(dinput);
|
||||||
if (!output) {
|
if (!doutput) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Since this input is linked, if the link is not between two shader nodes, it means that the
|
/* Since this input is linked, if the link is not between two shader nodes, it means that the
|
||||||
* node takes a buffer through this input and so we increment the number of input buffers. */
|
* node takes a buffer through this input and so we increment the number of input buffers. */
|
||||||
if (!is_shader_node(node) || !is_shader_node(output.node())) {
|
if (!is_shader_node(node) || !is_shader_node(doutput.node())) {
|
||||||
number_of_input_buffers++;
|
number_of_input_buffers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the number of buffers needed by the node dependency is more than the total number of
|
/* If the number of buffers needed by the node dependency is more than the total number of
|
||||||
* buffers needed by the dependencies, then update the latter to be the former. This is
|
* buffers needed by the dependencies, then update the latter to be the former. This is
|
||||||
* computing the "d" in the aforementioned equation "max(n + m, d)". */
|
* computing the "d" in the aforementioned equation "max(n + m, d)". */
|
||||||
const int buffers_needed_by_dependency = needed_buffers.lookup(output.node());
|
const int buffers_needed_by_dependency = needed_buffers.lookup(doutput.node());
|
||||||
if (buffers_needed_by_dependency > buffers_needed_by_dependencies) {
|
if (buffers_needed_by_dependency > buffers_needed_by_dependencies) {
|
||||||
buffers_needed_by_dependencies = buffers_needed_by_dependency;
|
buffers_needed_by_dependencies = buffers_needed_by_dependency;
|
||||||
}
|
}
|
||||||
@@ -181,17 +183,18 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node)
|
|||||||
|
|
||||||
/* Compute the number of buffers that will be computed/output by this node. */
|
/* Compute the number of buffers that will be computed/output by this node. */
|
||||||
int number_of_output_buffers = 0;
|
int number_of_output_buffers = 0;
|
||||||
for (const OutputSocketRef *output_ref : node->outputs()) {
|
for (const bNodeSocket *output : node->output_sockets()) {
|
||||||
const DOutputSocket output{node.context(), output_ref};
|
const DOutputSocket doutput{node.context(), output};
|
||||||
|
|
||||||
/* The output is not linked, it outputs no buffer. */
|
/* The output is not linked, it outputs no buffer. */
|
||||||
if (output->logically_linked_sockets().is_empty()) {
|
if (!output->is_logically_linked()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If any of the links is not between two shader nodes, it means that the node outputs
|
/* If any of the links is not between two shader nodes, it means that the node outputs
|
||||||
* a buffer through this output and so we increment the number of output buffers. */
|
* a buffer through this output and so we increment the number of output buffers. */
|
||||||
if (!is_output_linked_to_node_conditioned(output, is_shader_node) || !is_shader_node(node)) {
|
if (!is_output_linked_to_node_conditioned(doutput, is_shader_node) ||
|
||||||
|
!is_shader_node(node)) {
|
||||||
number_of_output_buffers++;
|
number_of_output_buffers++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,24 +258,24 @@ Schedule compute_schedule(DerivedNodeTree &tree)
|
|||||||
* want the node with the highest number of needed buffers to be schedule first, but since
|
* want the node with the highest number of needed buffers to be schedule first, but since
|
||||||
* those are pushed to the traversal stack, we need to push them in reverse order. */
|
* those are pushed to the traversal stack, we need to push them in reverse order. */
|
||||||
Vector<DNode> sorted_dependency_nodes;
|
Vector<DNode> sorted_dependency_nodes;
|
||||||
for (const InputSocketRef *input_ref : node->inputs()) {
|
for (const bNodeSocket *input : node->input_sockets()) {
|
||||||
const DInputSocket input{node.context(), input_ref};
|
const DInputSocket dinput{node.context(), input};
|
||||||
|
|
||||||
/* Get the output linked to the input. If it is null, that means the input is unlinked and
|
/* Get the output linked to the input. If it is null, that means the input is unlinked and
|
||||||
* has no dependency node, so skip it. */
|
* has no dependency node, so skip it. */
|
||||||
const DOutputSocket output = get_output_linked_to_input(input);
|
const DOutputSocket doutput = get_output_linked_to_input(dinput);
|
||||||
if (!output) {
|
if (!doutput) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The dependency node was added before, so skip it. The number of dependency nodes is very
|
/* The dependency node was added before, so skip it. The number of dependency nodes is very
|
||||||
* small, typically less than 3, so a linear search is okay. */
|
* small, typically less than 3, so a linear search is okay. */
|
||||||
if (sorted_dependency_nodes.contains(output.node())) {
|
if (sorted_dependency_nodes.contains(doutput.node())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The dependency node was already schedule, so skip it. */
|
/* The dependency node was already schedule, so skip it. */
|
||||||
if (schedule.contains(output.node())) {
|
if (schedule.contains(doutput.node())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +283,7 @@ Schedule compute_schedule(DerivedNodeTree &tree)
|
|||||||
* typically less than 3, so insertion sort is okay. */
|
* typically less than 3, so insertion sort is okay. */
|
||||||
int insertion_position = 0;
|
int insertion_position = 0;
|
||||||
for (int i = 0; i < sorted_dependency_nodes.size(); i++) {
|
for (int i = 0; i < sorted_dependency_nodes.size(); i++) {
|
||||||
if (needed_buffers.lookup(output.node()) >
|
if (needed_buffers.lookup(doutput.node()) >
|
||||||
needed_buffers.lookup(sorted_dependency_nodes[i])) {
|
needed_buffers.lookup(sorted_dependency_nodes[i])) {
|
||||||
insertion_position++;
|
insertion_position++;
|
||||||
}
|
}
|
||||||
@@ -288,7 +291,7 @@ Schedule compute_schedule(DerivedNodeTree &tree)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sorted_dependency_nodes.insert(insertion_position, output.node());
|
sorted_dependency_nodes.insert(insertion_position, doutput.node());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push the sorted dependency nodes to the node stack in order. */
|
/* Push the sorted dependency nodes to the node stack in order. */
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ const DNode &ShaderNode::node() const
|
|||||||
|
|
||||||
bNode &ShaderNode::bnode() const
|
bNode &ShaderNode::bnode() const
|
||||||
{
|
{
|
||||||
return *node_->bnode();
|
return const_cast<bNode &>(*node_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type)
|
static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type)
|
||||||
@@ -77,17 +77,17 @@ static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gpu_stack_vector_from_socket(float *vector, const SocketRef *socket)
|
static void gpu_stack_vector_from_socket(float *vector, const bNodeSocket *socket)
|
||||||
{
|
{
|
||||||
switch (socket->bsocket()->type) {
|
switch (socket->type) {
|
||||||
case SOCK_FLOAT:
|
case SOCK_FLOAT:
|
||||||
vector[0] = socket->default_value<bNodeSocketValueFloat>()->value;
|
vector[0] = socket->default_value_typed<bNodeSocketValueFloat>()->value;
|
||||||
return;
|
return;
|
||||||
case SOCK_VECTOR:
|
case SOCK_VECTOR:
|
||||||
copy_v3_v3(vector, socket->default_value<bNodeSocketValueVector>()->value);
|
copy_v3_v3(vector, socket->default_value_typed<bNodeSocketValueVector>()->value);
|
||||||
return;
|
return;
|
||||||
case SOCK_RGBA:
|
case SOCK_RGBA:
|
||||||
copy_v4_v4(vector, socket->default_value<bNodeSocketValueRGBA>()->value);
|
copy_v4_v4(vector, socket->default_value_typed<bNodeSocketValueRGBA>()->value);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
BLI_assert_unreachable();
|
BLI_assert_unreachable();
|
||||||
@@ -101,8 +101,8 @@ static void populate_gpu_node_stack(DSocket socket, GPUNodeStack &stack)
|
|||||||
/* This will be initialized later by the GPU material compiler or the compile method. */
|
/* This will be initialized later by the GPU material compiler or the compile method. */
|
||||||
stack.link = nullptr;
|
stack.link = nullptr;
|
||||||
|
|
||||||
stack.sockettype = socket->bsocket()->type;
|
stack.sockettype = socket->type;
|
||||||
stack.type = gpu_type_from_socket_type((eNodeSocketDatatype)socket->bsocket()->type);
|
stack.type = gpu_type_from_socket_type((eNodeSocketDatatype)socket->type);
|
||||||
|
|
||||||
if (socket->is_input()) {
|
if (socket->is_input()) {
|
||||||
const DInputSocket input(socket);
|
const DInputSocket input(socket);
|
||||||
@@ -117,10 +117,10 @@ static void populate_gpu_node_stack(DSocket socket, GPUNodeStack &stack)
|
|||||||
* unlinked input or an unlinked input of a group input node that the socket is linked to,
|
* unlinked input or an unlinked input of a group input node that the socket is linked to,
|
||||||
* otherwise, get the value from the socket itself. */
|
* otherwise, get the value from the socket itself. */
|
||||||
if (origin->is_input()) {
|
if (origin->is_input()) {
|
||||||
gpu_stack_vector_from_socket(stack.vec, origin.socket_ref());
|
gpu_stack_vector_from_socket(stack.vec, origin.bsocket());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gpu_stack_vector_from_socket(stack.vec, socket.socket_ref());
|
gpu_stack_vector_from_socket(stack.vec, socket.bsocket());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -132,10 +132,11 @@ void ShaderNode::populate_inputs()
|
|||||||
{
|
{
|
||||||
/* Reserve a stack for each input in addition to an extra stack at the end to mark the end of the
|
/* Reserve a stack for each input in addition to an extra stack at the end to mark the end of the
|
||||||
* array, as this is what the GPU module functions expect. */
|
* array, as this is what the GPU module functions expect. */
|
||||||
inputs_.resize(node_->inputs().size() + 1);
|
const int num_input_sockets = node_->input_sockets().size();
|
||||||
|
inputs_.resize(num_input_sockets + 1);
|
||||||
inputs_.last().end = true;
|
inputs_.last().end = true;
|
||||||
|
|
||||||
for (int i = 0; i < node_->inputs().size(); i++) {
|
for (int i = 0; i < num_input_sockets; i++) {
|
||||||
populate_gpu_node_stack(node_.input(i), inputs_[i]);
|
populate_gpu_node_stack(node_.input(i), inputs_[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,10 +145,11 @@ void ShaderNode::populate_outputs()
|
|||||||
{
|
{
|
||||||
/* Reserve a stack for each output in addition to an extra stack at the end to mark the end of
|
/* Reserve a stack for each output in addition to an extra stack at the end to mark the end of
|
||||||
* the array, as this is what the GPU module functions expect. */
|
* the array, as this is what the GPU module functions expect. */
|
||||||
outputs_.resize(node_->outputs().size() + 1);
|
const int num_output_sockets = node_->output_sockets().size();
|
||||||
|
outputs_.resize(num_output_sockets + 1);
|
||||||
outputs_.last().end = true;
|
outputs_.last().end = true;
|
||||||
|
|
||||||
for (int i = 0; i < node_->outputs().size(); i++) {
|
for (int i = 0; i < num_output_sockets; i++) {
|
||||||
populate_gpu_node_stack(node_.output(i), outputs_[i]);
|
populate_gpu_node_stack(node_.output(i), outputs_[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ void ShaderOperation::construct_material(void *thunk, GPUMaterial *material)
|
|||||||
{
|
{
|
||||||
ShaderOperation *operation = static_cast<ShaderOperation *>(thunk);
|
ShaderOperation *operation = static_cast<ShaderOperation *>(thunk);
|
||||||
for (DNode node : operation->compile_unit_) {
|
for (DNode node : operation->compile_unit_) {
|
||||||
ShaderNode *shader_node = node->typeinfo()->get_compositor_shader_node(node);
|
ShaderNode *shader_node = node->typeinfo->get_compositor_shader_node(node);
|
||||||
operation->shader_nodes_.add_new(node, std::unique_ptr<ShaderNode>(shader_node));
|
operation->shader_nodes_.add_new(node, std::unique_ptr<ShaderNode>(shader_node));
|
||||||
|
|
||||||
operation->link_node_inputs(node, material);
|
operation->link_node_inputs(node, material);
|
||||||
@@ -141,27 +141,27 @@ void ShaderOperation::construct_material(void *thunk, GPUMaterial *material)
|
|||||||
|
|
||||||
void ShaderOperation::link_node_inputs(DNode node, GPUMaterial *material)
|
void ShaderOperation::link_node_inputs(DNode node, GPUMaterial *material)
|
||||||
{
|
{
|
||||||
for (const InputSocketRef *input_ref : node->inputs()) {
|
for (const bNodeSocket *input : node->input_sockets()) {
|
||||||
const DInputSocket input{node.context(), input_ref};
|
const DInputSocket dinput{node.context(), input};
|
||||||
|
|
||||||
/* Get the output linked to the input. If it is null, that means the input is unlinked.
|
/* Get the output linked to the input. If it is null, that means the input is unlinked.
|
||||||
* Unlinked inputs are linked by the node compile method, so skip this here. */
|
* Unlinked inputs are linked by the node compile method, so skip this here. */
|
||||||
const DOutputSocket output = get_output_linked_to_input(input);
|
const DOutputSocket doutput = get_output_linked_to_input(dinput);
|
||||||
if (!output) {
|
if (!doutput) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the origin node is part of the shader operation, then the link is internal to the GPU
|
/* If the origin node is part of the shader operation, then the link is internal to the GPU
|
||||||
* material graph and is linked appropriately. */
|
* material graph and is linked appropriately. */
|
||||||
if (compile_unit_.contains(output.node())) {
|
if (compile_unit_.contains(doutput.node())) {
|
||||||
link_node_input_internal(input, output);
|
link_node_input_internal(dinput, doutput);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, the origin node is not part of the shader operation, then the link is external to
|
/* Otherwise, the origin node is not part of the shader operation, then the link is external to
|
||||||
* the GPU material graph and an input to the shader operation must be declared and linked to
|
* the GPU material graph and an input to the shader operation must be declared and linked to
|
||||||
* the node input. */
|
* the node input. */
|
||||||
link_node_input_external(input, output, material);
|
link_node_input_external(dinput, doutput, material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,10 +169,10 @@ void ShaderOperation::link_node_input_internal(DInputSocket input_socket,
|
|||||||
DOutputSocket output_socket)
|
DOutputSocket output_socket)
|
||||||
{
|
{
|
||||||
ShaderNode &output_node = *shader_nodes_.lookup(output_socket.node());
|
ShaderNode &output_node = *shader_nodes_.lookup(output_socket.node());
|
||||||
GPUNodeStack &output_stack = output_node.get_output(output_socket->identifier());
|
GPUNodeStack &output_stack = output_node.get_output(output_socket->identifier);
|
||||||
|
|
||||||
ShaderNode &input_node = *shader_nodes_.lookup(input_socket.node());
|
ShaderNode &input_node = *shader_nodes_.lookup(input_socket.node());
|
||||||
GPUNodeStack &input_stack = input_node.get_input(input_socket->identifier());
|
GPUNodeStack &input_stack = input_node.get_input(input_socket->identifier);
|
||||||
|
|
||||||
input_stack.link = output_stack.link;
|
input_stack.link = output_stack.link;
|
||||||
}
|
}
|
||||||
@@ -183,7 +183,7 @@ void ShaderOperation::link_node_input_external(DInputSocket input_socket,
|
|||||||
{
|
{
|
||||||
|
|
||||||
ShaderNode &node = *shader_nodes_.lookup(input_socket.node());
|
ShaderNode &node = *shader_nodes_.lookup(input_socket.node());
|
||||||
GPUNodeStack &stack = node.get_input(input_socket->identifier());
|
GPUNodeStack &stack = node.get_input(input_socket->identifier);
|
||||||
|
|
||||||
/* An input was already declared for that same output socket, so no need to declare it again. */
|
/* An input was already declared for that same output socket, so no need to declare it again. */
|
||||||
if (!output_to_material_attribute_map_.contains(output_socket)) {
|
if (!output_to_material_attribute_map_.contains(output_socket)) {
|
||||||
@@ -219,8 +219,8 @@ void ShaderOperation::declare_operation_input(DInputSocket input_socket,
|
|||||||
|
|
||||||
/* Declare the input descriptor for this input and prefer to declare its type to be the same as
|
/* Declare the input descriptor for this input and prefer to declare its type to be the same as
|
||||||
* the type of the output socket because doing type conversion in the shader is much cheaper. */
|
* the type of the output socket because doing type conversion in the shader is much cheaper. */
|
||||||
InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_socket.socket_ref());
|
InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_socket.bsocket());
|
||||||
input_descriptor.type = get_node_socket_result_type(output_socket.socket_ref());
|
input_descriptor.type = get_node_socket_result_type(output_socket.bsocket());
|
||||||
declare_input_descriptor(input_identifier, input_descriptor);
|
declare_input_descriptor(input_identifier, input_descriptor);
|
||||||
|
|
||||||
/* Add a new GPU attribute representing an input to the GPU material. Instead of using the
|
/* Add a new GPU attribute representing an input to the GPU material. Instead of using the
|
||||||
@@ -242,16 +242,16 @@ void ShaderOperation::declare_operation_input(DInputSocket input_socket,
|
|||||||
|
|
||||||
void ShaderOperation::populate_results_for_node(DNode node, GPUMaterial *material)
|
void ShaderOperation::populate_results_for_node(DNode node, GPUMaterial *material)
|
||||||
{
|
{
|
||||||
for (const OutputSocketRef *output_ref : node->outputs()) {
|
for (const bNodeSocket *output : node->output_sockets()) {
|
||||||
const DOutputSocket output{node.context(), output_ref};
|
const DOutputSocket doutput{node.context(), output};
|
||||||
|
|
||||||
/* If any of the nodes linked to the output are not part of the shader operation, then an
|
/* If any of the nodes linked to the output are not part of the shader operation, then an
|
||||||
* output result needs to be populated for it. */
|
* output result needs to be populated for it. */
|
||||||
const bool need_to_populate_result = is_output_linked_to_node_conditioned(
|
const bool need_to_populate_result = is_output_linked_to_node_conditioned(
|
||||||
output, [&](DNode node) { return !compile_unit_.contains(node); });
|
doutput, [&](DNode node) { return !compile_unit_.contains(node); });
|
||||||
|
|
||||||
if (need_to_populate_result) {
|
if (need_to_populate_result) {
|
||||||
populate_operation_result(output, material);
|
populate_operation_result(doutput, material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,7 +276,7 @@ void ShaderOperation::populate_operation_result(DOutputSocket output_socket, GPU
|
|||||||
const unsigned int output_id = output_sockets_to_output_identifiers_map_.size();
|
const unsigned int output_id = output_sockets_to_output_identifiers_map_.size();
|
||||||
std::string output_identifier = "output" + std::to_string(output_id);
|
std::string output_identifier = "output" + std::to_string(output_id);
|
||||||
|
|
||||||
const ResultType result_type = get_node_socket_result_type(output_socket.socket_ref());
|
const ResultType result_type = get_node_socket_result_type(output_socket.bsocket());
|
||||||
const Result result = Result(result_type, texture_pool());
|
const Result result = Result(result_type, texture_pool());
|
||||||
populate_result(output_identifier, result);
|
populate_result(output_identifier, result);
|
||||||
|
|
||||||
@@ -284,7 +284,7 @@ void ShaderOperation::populate_operation_result(DOutputSocket output_socket, GPU
|
|||||||
output_sockets_to_output_identifiers_map_.add_new(output_socket, output_identifier);
|
output_sockets_to_output_identifiers_map_.add_new(output_socket, output_identifier);
|
||||||
|
|
||||||
ShaderNode &node = *shader_nodes_.lookup(output_socket.node());
|
ShaderNode &node = *shader_nodes_.lookup(output_socket.node());
|
||||||
GPUNodeLink *output_link = node.get_output(output_socket->identifier()).link;
|
GPUNodeLink *output_link = node.get_output(output_socket->identifier).link;
|
||||||
|
|
||||||
/* Link the output node stack to an output storer storing in the appropriate result. The result
|
/* Link the output node stack to an output storer storing in the appropriate result. The result
|
||||||
* is identified by its index in the operation and the index is encoded as a float to be passed
|
* is identified by its index in the operation and the index is encoded as a float to be passed
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ using TargetSocketPathInfo = DOutputSocket::TargetSocketPathInfo;
|
|||||||
DSocket get_input_origin_socket(DInputSocket input)
|
DSocket get_input_origin_socket(DInputSocket input)
|
||||||
{
|
{
|
||||||
/* The input is unlinked. Return the socket itself. */
|
/* The input is unlinked. Return the socket itself. */
|
||||||
if (input->logically_linked_sockets().is_empty()) {
|
if (!input->is_logically_linked()) {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,9 +52,9 @@ DOutputSocket get_output_linked_to_input(DInputSocket input)
|
|||||||
return DOutputSocket(origin);
|
return DOutputSocket(origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultType get_node_socket_result_type(const SocketRef *socket)
|
ResultType get_node_socket_result_type(const bNodeSocket *socket)
|
||||||
{
|
{
|
||||||
switch (socket->bsocket()->type) {
|
switch (socket->type) {
|
||||||
case SOCK_FLOAT:
|
case SOCK_FLOAT:
|
||||||
return ResultType::Float;
|
return ResultType::Float;
|
||||||
case SOCK_VECTOR:
|
case SOCK_VECTOR:
|
||||||
@@ -95,21 +95,20 @@ int number_of_inputs_linked_to_output_conditioned(DOutputSocket output,
|
|||||||
|
|
||||||
bool is_shader_node(DNode node)
|
bool is_shader_node(DNode node)
|
||||||
{
|
{
|
||||||
return node->typeinfo()->get_compositor_shader_node;
|
return node->typeinfo->get_compositor_shader_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_node_supported(DNode node)
|
bool is_node_supported(DNode node)
|
||||||
{
|
{
|
||||||
return node->typeinfo()->get_compositor_operation ||
|
return node->typeinfo->get_compositor_operation || node->typeinfo->get_compositor_shader_node;
|
||||||
node->typeinfo()->get_compositor_shader_node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InputDescriptor input_descriptor_from_input_socket(const InputSocketRef *socket)
|
InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket)
|
||||||
{
|
{
|
||||||
using namespace nodes;
|
using namespace nodes;
|
||||||
InputDescriptor input_descriptor;
|
InputDescriptor input_descriptor;
|
||||||
input_descriptor.type = get_node_socket_result_type(socket);
|
input_descriptor.type = get_node_socket_result_type(socket);
|
||||||
const NodeDeclaration *node_declaration = socket->node().declaration();
|
const NodeDeclaration *node_declaration = socket->owner_node().declaration();
|
||||||
/* Not every node have a declaration, in which case, we assume the default values for the rest of
|
/* Not every node have a declaration, in which case, we assume the default values for the rest of
|
||||||
* the properties. */
|
* the properties. */
|
||||||
if (!node_declaration) {
|
if (!node_declaration) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "BKE_lib_id.h"
|
#include "BKE_lib_id.h"
|
||||||
#include "BKE_main.h"
|
#include "BKE_main.h"
|
||||||
#include "BKE_node.h"
|
#include "BKE_node.h"
|
||||||
|
#include "BKE_node_runtime.hh"
|
||||||
#include "BKE_node_tree_update.h"
|
#include "BKE_node_tree_update.h"
|
||||||
#include "BKE_screen.h"
|
#include "BKE_screen.h"
|
||||||
|
|
||||||
@@ -46,14 +47,11 @@
|
|||||||
#include "BLT_translation.h"
|
#include "BLT_translation.h"
|
||||||
|
|
||||||
#include "NOD_node_declaration.hh"
|
#include "NOD_node_declaration.hh"
|
||||||
#include "NOD_node_tree_ref.hh"
|
|
||||||
#include "NOD_socket_declarations.hh"
|
#include "NOD_socket_declarations.hh"
|
||||||
#include "NOD_socket_declarations_geometry.hh"
|
#include "NOD_socket_declarations_geometry.hh"
|
||||||
|
|
||||||
#include "node_intern.hh" /* own include */
|
#include "node_intern.hh" /* own include */
|
||||||
|
|
||||||
using namespace blender::nodes::node_tree_ref_types;
|
|
||||||
|
|
||||||
struct bNodeListItem {
|
struct bNodeListItem {
|
||||||
struct bNodeListItem *next, *prev;
|
struct bNodeListItem *next, *prev;
|
||||||
struct bNode *node;
|
struct bNode *node;
|
||||||
@@ -434,18 +432,18 @@ namespace viewer_linking {
|
|||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
/* Depending on the node tree type, different socket types are supported by viewer nodes. */
|
/* Depending on the node tree type, different socket types are supported by viewer nodes. */
|
||||||
static bool socket_can_be_viewed(const OutputSocketRef &socket)
|
static bool socket_can_be_viewed(const bNodeSocket &socket)
|
||||||
{
|
{
|
||||||
if (nodeSocketIsHidden(socket.bsocket())) {
|
if (nodeSocketIsHidden(&socket)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (socket.idname() == "NodeSocketVirtual") {
|
if (STREQ(socket.idname, "NodeSocketVirtual")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (socket.tree().btree()->type != NTREE_GEOMETRY) {
|
if (socket.owner_tree().type != NTREE_GEOMETRY) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return ELEM(socket.typeinfo()->type,
|
return ELEM(socket.typeinfo->type,
|
||||||
SOCK_GEOMETRY,
|
SOCK_GEOMETRY,
|
||||||
SOCK_FLOAT,
|
SOCK_FLOAT,
|
||||||
SOCK_VECTOR,
|
SOCK_VECTOR,
|
||||||
@@ -502,15 +500,15 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_viewer_node(const NodeRef &node)
|
static bool is_viewer_node(const bNode &node)
|
||||||
{
|
{
|
||||||
return ELEM(node.bnode()->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER);
|
return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree)
|
static Vector<const bNode *> find_viewer_nodes(const bNodeTree &tree)
|
||||||
{
|
{
|
||||||
Vector<const NodeRef *> viewer_nodes;
|
Vector<const bNode *> viewer_nodes;
|
||||||
for (const NodeRef *node : tree.nodes()) {
|
for (const bNode *node : tree.all_nodes()) {
|
||||||
if (is_viewer_node(*node)) {
|
if (is_viewer_node(*node)) {
|
||||||
viewer_nodes.append(node);
|
viewer_nodes.append(node);
|
||||||
}
|
}
|
||||||
@@ -518,20 +516,20 @@ static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree)
|
|||||||
return viewer_nodes;
|
return viewer_nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_viewer_socket_in_viewer(const InputSocketRef &socket)
|
static bool is_viewer_socket_in_viewer(const bNodeSocket &socket)
|
||||||
{
|
{
|
||||||
const NodeRef &node = socket.node();
|
const bNode &node = socket.owner_node();
|
||||||
BLI_assert(is_viewer_node(node));
|
BLI_assert(is_viewer_node(node));
|
||||||
if (node.typeinfo()->type == GEO_NODE_VIEWER) {
|
if (node.typeinfo->type == GEO_NODE_VIEWER) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return socket.index() == 0;
|
return socket.index() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_linked_to_viewer(const OutputSocketRef &socket, const NodeRef &viewer_node)
|
static bool is_linked_to_viewer(const bNodeSocket &socket, const bNode &viewer_node)
|
||||||
{
|
{
|
||||||
for (const InputSocketRef *target_socket : socket.directly_linked_sockets()) {
|
for (const bNodeSocket *target_socket : socket.directly_linked_sockets()) {
|
||||||
if (&target_socket->node() != &viewer_node) {
|
if (&target_socket->owner_node() != &viewer_node) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!target_socket->is_available()) {
|
if (!target_socket->is_available()) {
|
||||||
@@ -561,39 +559,39 @@ static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const NodeRef *get_existing_viewer(const NodeTreeRef &tree)
|
static const bNode *get_existing_viewer(const bNodeTree &tree)
|
||||||
{
|
{
|
||||||
Vector<const NodeRef *> viewer_nodes = find_viewer_nodes(tree);
|
Vector<const bNode *> viewer_nodes = find_viewer_nodes(tree);
|
||||||
|
|
||||||
/* Check if there is already an active viewer node that should be used. */
|
/* Check if there is already an active viewer node that should be used. */
|
||||||
for (const NodeRef *viewer_node : viewer_nodes) {
|
for (const bNode *viewer_node : viewer_nodes) {
|
||||||
if (viewer_node->bnode()->flag & NODE_DO_OUTPUT) {
|
if (viewer_node->flag & NODE_DO_OUTPUT) {
|
||||||
return viewer_node;
|
return viewer_node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no active but non-active viewers exist, make one active. */
|
/* If no active but non-active viewers exist, make one active. */
|
||||||
if (!viewer_nodes.is_empty()) {
|
if (!viewer_nodes.is_empty()) {
|
||||||
viewer_nodes[0]->bnode()->flag |= NODE_DO_OUTPUT;
|
const_cast<bNode *>(viewer_nodes[0])->flag |= NODE_DO_OUTPUT;
|
||||||
return viewer_nodes[0];
|
return viewer_nodes[0];
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *active_viewer_node,
|
static const bNodeSocket *find_output_socket_to_be_viewed(const bNode *active_viewer_node,
|
||||||
const NodeRef &node_to_view)
|
const bNode &node_to_view)
|
||||||
{
|
{
|
||||||
/* Check if any of the output sockets is selected, which is the case when the user just clicked
|
/* Check if any of the output sockets is selected, which is the case when the user just clicked
|
||||||
* on the socket. */
|
* on the socket. */
|
||||||
for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
|
for (const bNodeSocket *output_socket : node_to_view.output_sockets()) {
|
||||||
if (output_socket->bsocket()->flag & SELECT) {
|
if (output_socket->flag & SELECT) {
|
||||||
return output_socket;
|
return output_socket;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const OutputSocketRef *last_socket_linked_to_viewer = nullptr;
|
const bNodeSocket *last_socket_linked_to_viewer = nullptr;
|
||||||
if (active_viewer_node != nullptr) {
|
if (active_viewer_node != nullptr) {
|
||||||
for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
|
for (const bNodeSocket *output_socket : node_to_view.output_sockets()) {
|
||||||
if (!socket_can_be_viewed(*output_socket)) {
|
if (!socket_can_be_viewed(*output_socket)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -604,7 +602,7 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act
|
|||||||
}
|
}
|
||||||
if (last_socket_linked_to_viewer == nullptr) {
|
if (last_socket_linked_to_viewer == nullptr) {
|
||||||
/* If no output is connected to a viewer, use the first output that can be viewed. */
|
/* If no output is connected to a viewer, use the first output that can be viewed. */
|
||||||
for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
|
for (const bNodeSocket *output_socket : node_to_view.output_sockets()) {
|
||||||
if (socket_can_be_viewed(*output_socket)) {
|
if (socket_can_be_viewed(*output_socket)) {
|
||||||
return output_socket;
|
return output_socket;
|
||||||
}
|
}
|
||||||
@@ -612,10 +610,10 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Pick the next socket to be linked to the viewer. */
|
/* Pick the next socket to be linked to the viewer. */
|
||||||
const int tot_outputs = node_to_view.outputs().size();
|
const int tot_outputs = node_to_view.output_sockets().size();
|
||||||
for (const int offset : IndexRange(1, tot_outputs - 1)) {
|
for (const int offset : IndexRange(1, tot_outputs - 1)) {
|
||||||
const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs;
|
const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs;
|
||||||
const OutputSocketRef &output_socket = node_to_view.output(index);
|
const bNodeSocket &output_socket = node_to_view.output_socket(index);
|
||||||
if (!socket_can_be_viewed(output_socket)) {
|
if (!socket_can_be_viewed(output_socket)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -682,20 +680,15 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view)
|
|||||||
{
|
{
|
||||||
SpaceNode &snode = *CTX_wm_space_node(&C);
|
SpaceNode &snode = *CTX_wm_space_node(&C);
|
||||||
bNodeTree *btree = snode.edittree;
|
bNodeTree *btree = snode.edittree;
|
||||||
|
btree->ensure_topology_cache();
|
||||||
|
|
||||||
const NodeTreeRef tree{btree};
|
bNode *active_viewer_bnode = const_cast<bNode *>(get_existing_viewer(*btree));
|
||||||
const NodeRef &node_to_view = *tree.find_node(bnode_to_view);
|
bNodeSocket *bsocket_to_view = const_cast<bNodeSocket *>(
|
||||||
const NodeRef *active_viewer_node = get_existing_viewer(tree);
|
find_output_socket_to_be_viewed(active_viewer_bnode, bnode_to_view));
|
||||||
|
if (bsocket_to_view == nullptr) {
|
||||||
const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node,
|
|
||||||
node_to_view);
|
|
||||||
if (socket_to_view == nullptr) {
|
|
||||||
return OPERATOR_FINISHED;
|
return OPERATOR_FINISHED;
|
||||||
}
|
}
|
||||||
|
return link_socket_to_viewer(C, active_viewer_bnode, bnode_to_view, *bsocket_to_view);
|
||||||
bNodeSocket &bsocket_to_view = *socket_to_view->bsocket();
|
|
||||||
bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr;
|
|
||||||
return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
@@ -2048,7 +2041,7 @@ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketIn
|
|||||||
|
|
||||||
/* Try to get the main socket based on the socket declaration. */
|
/* Try to get the main socket based on the socket declaration. */
|
||||||
nodeDeclarationEnsure(&ntree, &node);
|
nodeDeclarationEnsure(&ntree, &node);
|
||||||
const nodes::NodeDeclaration *node_decl = node.runtime->declaration;
|
const nodes::NodeDeclaration *node_decl = node.declaration();
|
||||||
if (node_decl != nullptr) {
|
if (node_decl != nullptr) {
|
||||||
Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
|
Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
|
||||||
node_decl->outputs();
|
node_decl->outputs();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "BKE_image.h"
|
#include "BKE_image.h"
|
||||||
#include "BKE_node.h"
|
#include "BKE_node.h"
|
||||||
|
#include "BKE_node_runtime.hh"
|
||||||
|
|
||||||
#include "BLI_map.hh"
|
#include "BLI_map.hh"
|
||||||
#include "BLI_math_vector.h"
|
#include "BLI_math_vector.h"
|
||||||
@@ -15,8 +16,6 @@
|
|||||||
#include "DNA_material_types.h"
|
#include "DNA_material_types.h"
|
||||||
#include "DNA_node_types.h"
|
#include "DNA_node_types.h"
|
||||||
|
|
||||||
#include "NOD_node_tree_ref.hh"
|
|
||||||
|
|
||||||
#include "obj_export_mesh.hh"
|
#include "obj_export_mesh.hh"
|
||||||
#include "obj_export_mtl.hh"
|
#include "obj_export_mtl.hh"
|
||||||
|
|
||||||
@@ -84,25 +83,25 @@ static void copy_property_from_node(const eNodeSocketDatatype property_type,
|
|||||||
* Collect all the source sockets linked to the destination socket in a destination node.
|
* Collect all the source sockets linked to the destination socket in a destination node.
|
||||||
*/
|
*/
|
||||||
static void linked_sockets_to_dest_id(const bNode *dest_node,
|
static void linked_sockets_to_dest_id(const bNode *dest_node,
|
||||||
const nodes::NodeTreeRef &node_tree,
|
const bNodeTree &node_tree,
|
||||||
const char *dest_socket_id,
|
const char *dest_socket_id,
|
||||||
Vector<const nodes::OutputSocketRef *> &r_linked_sockets)
|
Vector<const bNodeSocket *> &r_linked_sockets)
|
||||||
{
|
{
|
||||||
r_linked_sockets.clear();
|
r_linked_sockets.clear();
|
||||||
if (!dest_node) {
|
if (!dest_node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Span<const nodes::NodeRef *> object_dest_nodes = node_tree.nodes_by_type(dest_node->idname);
|
Span<const bNode *> object_dest_nodes = node_tree.nodes_by_type(dest_node->idname);
|
||||||
Span<const nodes::InputSocketRef *> dest_inputs = object_dest_nodes.first()->inputs();
|
Span<const bNodeSocket *> dest_inputs = object_dest_nodes.first()->input_sockets();
|
||||||
const nodes::InputSocketRef *dest_socket = nullptr;
|
const bNodeSocket *dest_socket = nullptr;
|
||||||
for (const nodes::InputSocketRef *curr_socket : dest_inputs) {
|
for (const bNodeSocket *curr_socket : dest_inputs) {
|
||||||
if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id)) {
|
if (STREQ(curr_socket->identifier, dest_socket_id)) {
|
||||||
dest_socket = curr_socket;
|
dest_socket = curr_socket;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dest_socket) {
|
if (dest_socket) {
|
||||||
Span<const nodes::OutputSocketRef *> linked_sockets = dest_socket->directly_linked_sockets();
|
Span<const bNodeSocket *> linked_sockets = dest_socket->directly_linked_sockets();
|
||||||
r_linked_sockets.resize(linked_sockets.size());
|
r_linked_sockets.resize(linked_sockets.size());
|
||||||
r_linked_sockets = linked_sockets;
|
r_linked_sockets = linked_sockets;
|
||||||
}
|
}
|
||||||
@@ -111,13 +110,12 @@ static void linked_sockets_to_dest_id(const bNode *dest_node,
|
|||||||
/**
|
/**
|
||||||
* From a list of sockets, get the parent node which is of the given node type.
|
* From a list of sockets, get the parent node which is of the given node type.
|
||||||
*/
|
*/
|
||||||
static const bNode *get_node_of_type(Span<const nodes::OutputSocketRef *> sockets_list,
|
static const bNode *get_node_of_type(Span<const bNodeSocket *> sockets_list, const int node_type)
|
||||||
const int node_type)
|
|
||||||
{
|
{
|
||||||
for (const nodes::SocketRef *socket : sockets_list) {
|
for (const bNodeSocket *socket : sockets_list) {
|
||||||
const bNode *parent_node = socket->bnode();
|
const bNode &parent_node = socket->owner_node();
|
||||||
if (parent_node->typeinfo->type == node_type) {
|
if (parent_node.typeinfo->type == node_type) {
|
||||||
return parent_node;
|
return &parent_node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -153,16 +151,16 @@ static const char *get_image_filepath(const bNode *tex_node)
|
|||||||
* We only want one that feeds directly into a Material Output node
|
* We only want one that feeds directly into a Material Output node
|
||||||
* (that is the behavior of the legacy Python exporter).
|
* (that is the behavior of the legacy Python exporter).
|
||||||
*/
|
*/
|
||||||
static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree)
|
static const bNode *find_bsdf_node(const bNodeTree *nodetree)
|
||||||
{
|
{
|
||||||
if (!nodetree) {
|
if (!nodetree) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
for (const nodes::NodeRef *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) {
|
for (const bNode *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) {
|
||||||
const nodes::InputSocketRef *node_input_socket0 = node->inputs()[0];
|
const bNodeSocket &node_input_socket0 = node->input_socket(0);
|
||||||
for (const nodes::OutputSocketRef *out_sock : node_input_socket0->directly_linked_sockets()) {
|
for (const bNodeSocket *out_sock : node_input_socket0.directly_linked_sockets()) {
|
||||||
const nodes::NodeRef &in_node = out_sock->node();
|
const bNode &in_node = out_sock->owner_node();
|
||||||
if (in_node.typeinfo()->type == SH_NODE_BSDF_PRINCIPLED) {
|
if (in_node.typeinfo->type == SH_NODE_BSDF_PRINCIPLED) {
|
||||||
return &in_node;
|
return &in_node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,55 +171,50 @@ static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree)
|
|||||||
/**
|
/**
|
||||||
* Store properties found either in bNode or material into r_mtl_mat.
|
* Store properties found either in bNode or material into r_mtl_mat.
|
||||||
*/
|
*/
|
||||||
static void store_bsdf_properties(const nodes::NodeRef *bsdf_node,
|
static void store_bsdf_properties(const bNode *bsdf_node,
|
||||||
const Material *material,
|
const Material *material,
|
||||||
MTLMaterial &r_mtl_mat)
|
MTLMaterial &r_mtl_mat)
|
||||||
{
|
{
|
||||||
const bNode *bnode = nullptr;
|
|
||||||
if (bsdf_node) {
|
|
||||||
bnode = bsdf_node->bnode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If p-BSDF is not present, fallback to #Object.Material. */
|
/* If p-BSDF is not present, fallback to #Object.Material. */
|
||||||
float roughness = material->roughness;
|
float roughness = material->roughness;
|
||||||
if (bnode) {
|
if (bsdf_node) {
|
||||||
copy_property_from_node(SOCK_FLOAT, bnode, "Roughness", {&roughness, 1});
|
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Roughness", {&roughness, 1});
|
||||||
}
|
}
|
||||||
/* Empirical approximation. Importer should use the inverse of this method. */
|
/* Empirical approximation. Importer should use the inverse of this method. */
|
||||||
float spec_exponent = (1.0f - roughness);
|
float spec_exponent = (1.0f - roughness);
|
||||||
spec_exponent *= spec_exponent * 1000.0f;
|
spec_exponent *= spec_exponent * 1000.0f;
|
||||||
|
|
||||||
float specular = material->spec;
|
float specular = material->spec;
|
||||||
if (bnode) {
|
if (bsdf_node) {
|
||||||
copy_property_from_node(SOCK_FLOAT, bnode, "Specular", {&specular, 1});
|
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Specular", {&specular, 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
float metallic = material->metallic;
|
float metallic = material->metallic;
|
||||||
if (bnode) {
|
if (bsdf_node) {
|
||||||
copy_property_from_node(SOCK_FLOAT, bnode, "Metallic", {&metallic, 1});
|
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Metallic", {&metallic, 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
float refraction_index = 1.0f;
|
float refraction_index = 1.0f;
|
||||||
if (bnode) {
|
if (bsdf_node) {
|
||||||
copy_property_from_node(SOCK_FLOAT, bnode, "IOR", {&refraction_index, 1});
|
copy_property_from_node(SOCK_FLOAT, bsdf_node, "IOR", {&refraction_index, 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
float dissolved = material->a;
|
float dissolved = material->a;
|
||||||
if (bnode) {
|
if (bsdf_node) {
|
||||||
copy_property_from_node(SOCK_FLOAT, bnode, "Alpha", {&dissolved, 1});
|
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Alpha", {&dissolved, 1});
|
||||||
}
|
}
|
||||||
const bool transparent = dissolved != 1.0f;
|
const bool transparent = dissolved != 1.0f;
|
||||||
|
|
||||||
float3 diffuse_col = {material->r, material->g, material->b};
|
float3 diffuse_col = {material->r, material->g, material->b};
|
||||||
if (bnode) {
|
if (bsdf_node) {
|
||||||
copy_property_from_node(SOCK_RGBA, bnode, "Base Color", {diffuse_col, 3});
|
copy_property_from_node(SOCK_RGBA, bsdf_node, "Base Color", {diffuse_col, 3});
|
||||||
}
|
}
|
||||||
|
|
||||||
float3 emission_col{0.0f};
|
float3 emission_col{0.0f};
|
||||||
float emission_strength = 0.0f;
|
float emission_strength = 0.0f;
|
||||||
if (bnode) {
|
if (bsdf_node) {
|
||||||
copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1});
|
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1});
|
||||||
copy_property_from_node(SOCK_RGBA, bnode, "Emission", {emission_col, 3});
|
copy_property_from_node(SOCK_RGBA, bsdf_node, "Emission", {emission_col, 3});
|
||||||
}
|
}
|
||||||
mul_v3_fl(emission_col, emission_strength);
|
mul_v3_fl(emission_col, emission_strength);
|
||||||
|
|
||||||
@@ -265,8 +258,8 @@ static void store_bsdf_properties(const nodes::NodeRef *bsdf_node,
|
|||||||
/**
|
/**
|
||||||
* Store image texture options and file-paths in `r_mtl_mat`.
|
* Store image texture options and file-paths in `r_mtl_mat`.
|
||||||
*/
|
*/
|
||||||
static void store_image_textures(const nodes::NodeRef *bsdf_node,
|
static void store_image_textures(const bNode *bsdf_node,
|
||||||
const nodes::NodeTreeRef *node_tree,
|
const bNodeTree *node_tree,
|
||||||
const Material *material,
|
const Material *material,
|
||||||
MTLMaterial &r_mtl_mat)
|
MTLMaterial &r_mtl_mat)
|
||||||
{
|
{
|
||||||
@@ -274,7 +267,6 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node,
|
|||||||
/* No nodetree, no images, or no Principled BSDF node. */
|
/* No nodetree, no images, or no Principled BSDF node. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const bNode *bnode = bsdf_node->bnode();
|
|
||||||
|
|
||||||
/* Normal Map Texture has two extra tasks of:
|
/* Normal Map Texture has two extra tasks of:
|
||||||
* - finding a Normal Map node before finding a texture node.
|
* - finding a Normal Map node before finding a texture node.
|
||||||
@@ -283,12 +275,12 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node,
|
|||||||
|
|
||||||
for (int key = 0; key < (int)MTLTexMapType::Count; ++key) {
|
for (int key = 0; key < (int)MTLTexMapType::Count; ++key) {
|
||||||
MTLTexMap &value = r_mtl_mat.texture_maps[key];
|
MTLTexMap &value = r_mtl_mat.texture_maps[key];
|
||||||
Vector<const nodes::OutputSocketRef *> linked_sockets;
|
Vector<const bNodeSocket *> linked_sockets;
|
||||||
const bNode *normal_map_node{nullptr};
|
const bNode *normal_map_node{nullptr};
|
||||||
|
|
||||||
if (key == (int)MTLTexMapType::bump) {
|
if (key == (int)MTLTexMapType::bump) {
|
||||||
/* Find sockets linked to destination "Normal" socket in P-BSDF node. */
|
/* Find sockets linked to destination "Normal" socket in P-BSDF node. */
|
||||||
linked_sockets_to_dest_id(bnode, *node_tree, "Normal", linked_sockets);
|
linked_sockets_to_dest_id(bsdf_node, *node_tree, "Normal", linked_sockets);
|
||||||
/* Among the linked sockets, find Normal Map shader node. */
|
/* Among the linked sockets, find Normal Map shader node. */
|
||||||
normal_map_node = get_node_of_type(linked_sockets, SH_NODE_NORMAL_MAP);
|
normal_map_node = get_node_of_type(linked_sockets, SH_NODE_NORMAL_MAP);
|
||||||
|
|
||||||
@@ -299,13 +291,15 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node,
|
|||||||
/* Skip emission map if emission strength is zero. */
|
/* Skip emission map if emission strength is zero. */
|
||||||
if (key == (int)MTLTexMapType::Ke) {
|
if (key == (int)MTLTexMapType::Ke) {
|
||||||
float emission_strength = 0.0f;
|
float emission_strength = 0.0f;
|
||||||
copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1});
|
copy_property_from_node(
|
||||||
|
SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1});
|
||||||
if (emission_strength == 0.0f) {
|
if (emission_strength == 0.0f) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Find sockets linked to the destination socket of interest, in P-BSDF node. */
|
/* Find sockets linked to the destination socket of interest, in P-BSDF node. */
|
||||||
linked_sockets_to_dest_id(bnode, *node_tree, tex_map_type_to_socket_id[key], linked_sockets);
|
linked_sockets_to_dest_id(
|
||||||
|
bsdf_node, *node_tree, tex_map_type_to_socket_id[key], linked_sockets);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Among the linked sockets, find Image Texture shader node. */
|
/* Among the linked sockets, find Image Texture shader node. */
|
||||||
@@ -341,14 +335,14 @@ MTLMaterial mtlmaterial_for_material(const Material *material)
|
|||||||
MTLMaterial mtlmat;
|
MTLMaterial mtlmat;
|
||||||
mtlmat.name = std::string(material->id.name + 2);
|
mtlmat.name = std::string(material->id.name + 2);
|
||||||
std::replace(mtlmat.name.begin(), mtlmat.name.end(), ' ', '_');
|
std::replace(mtlmat.name.begin(), mtlmat.name.end(), ' ', '_');
|
||||||
const nodes::NodeTreeRef *nodetree = nullptr;
|
const bNodeTree *nodetree = material->nodetree;
|
||||||
if (material->nodetree) {
|
if (nodetree != nullptr) {
|
||||||
nodetree = new nodes::NodeTreeRef(material->nodetree);
|
nodetree->ensure_topology_cache();
|
||||||
}
|
}
|
||||||
const nodes::NodeRef *bsdf_node = find_bsdf_node(nodetree);
|
|
||||||
|
const bNode *bsdf_node = find_bsdf_node(nodetree);
|
||||||
store_bsdf_properties(bsdf_node, material, mtlmat);
|
store_bsdf_properties(bsdf_node, material, mtlmat);
|
||||||
store_image_textures(bsdf_node, nodetree, material, mtlmat);
|
store_image_textures(bsdf_node, nodetree, material, mtlmat);
|
||||||
delete nodetree;
|
|
||||||
return mtlmat;
|
return mtlmat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,33 @@
|
|||||||
#include "DNA_scene_types.h" /* for #ImageFormatData */
|
#include "DNA_scene_types.h" /* for #ImageFormatData */
|
||||||
#include "DNA_vec_types.h" /* for #rctf */
|
#include "DNA_vec_types.h" /* for #rctf */
|
||||||
|
|
||||||
|
/** Workaround to forward-declare C++ type in C header. */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
namespace blender {
|
||||||
|
template<typename T> class Span;
|
||||||
|
class StringRef;
|
||||||
|
class StringRefNull;
|
||||||
|
} // namespace blender
|
||||||
|
namespace blender::nodes {
|
||||||
|
class NodeDeclaration;
|
||||||
|
class SocketDeclaration;
|
||||||
|
} // namespace blender::nodes
|
||||||
|
namespace blender::bke {
|
||||||
|
class bNodeTreeRuntime;
|
||||||
|
class bNodeRuntime;
|
||||||
|
class bNodeSocketRuntime;
|
||||||
|
} // namespace blender::bke
|
||||||
|
using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
|
||||||
|
using SocketDeclarationHandle = blender::nodes::SocketDeclaration;
|
||||||
|
using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime;
|
||||||
|
using bNodeRuntimeHandle = blender::bke::bNodeRuntime;
|
||||||
|
using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime;
|
||||||
|
#else
|
||||||
|
typedef struct NodeDeclarationHandle NodeDeclarationHandle;
|
||||||
|
typedef struct SocketDeclarationHandle SocketDeclarationHandle;
|
||||||
|
typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle;
|
||||||
|
typedef struct bNodeRuntimeHandle bNodeRuntimeHandle;
|
||||||
|
typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct AnimData;
|
struct AnimData;
|
||||||
@@ -30,6 +55,7 @@ struct bNodeLink;
|
|||||||
struct bNodePreview;
|
struct bNodePreview;
|
||||||
struct bNodeTreeExec;
|
struct bNodeTreeExec;
|
||||||
struct bNodeType;
|
struct bNodeType;
|
||||||
|
struct bNode;
|
||||||
struct uiBlock;
|
struct uiBlock;
|
||||||
|
|
||||||
#define NODE_MAXSTR 64
|
#define NODE_MAXSTR 64
|
||||||
@@ -65,30 +91,6 @@ typedef struct bNodeStack {
|
|||||||
#define NS_CR_FIT 4
|
#define NS_CR_FIT 4
|
||||||
#define NS_CR_STRETCH 5
|
#define NS_CR_STRETCH 5
|
||||||
|
|
||||||
/** Workaround to forward-declare C++ type in C header. */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
namespace blender::nodes {
|
|
||||||
class NodeDeclaration;
|
|
||||||
class SocketDeclaration;
|
|
||||||
} // namespace blender::nodes
|
|
||||||
namespace blender::bke {
|
|
||||||
class bNodeTreeRuntime;
|
|
||||||
class bNodeRuntime;
|
|
||||||
class bNodeSocketRuntime;
|
|
||||||
} // namespace blender::bke
|
|
||||||
using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
|
|
||||||
using SocketDeclarationHandle = blender::nodes::SocketDeclaration;
|
|
||||||
using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime;
|
|
||||||
using bNodeRuntimeHandle = blender::bke::bNodeRuntime;
|
|
||||||
using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime;
|
|
||||||
#else
|
|
||||||
typedef struct NodeDeclarationHandle NodeDeclarationHandle;
|
|
||||||
typedef struct SocketDeclarationHandle SocketDeclarationHandle;
|
|
||||||
typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle;
|
|
||||||
typedef struct bNodeRuntimeHandle bNodeRuntimeHandle;
|
|
||||||
typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct bNodeSocket {
|
typedef struct bNodeSocket {
|
||||||
struct bNodeSocket *next, *prev;
|
struct bNodeSocket *next, *prev;
|
||||||
|
|
||||||
@@ -181,6 +183,49 @@ typedef struct bNodeSocket {
|
|||||||
bNodeStack ns DNA_DEPRECATED;
|
bNodeStack ns DNA_DEPRECATED;
|
||||||
|
|
||||||
bNodeSocketRuntimeHandle *runtime;
|
bNodeSocketRuntimeHandle *runtime;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
bool is_available() const;
|
||||||
|
bool is_multi_input() const;
|
||||||
|
bool is_input() const;
|
||||||
|
bool is_output() const;
|
||||||
|
|
||||||
|
/** Utility to access the value of the socket. */
|
||||||
|
template<typename T> const T *default_value_typed() const;
|
||||||
|
|
||||||
|
/* The following methods are only available when #bNodeTree.ensure_topology_cache has been
|
||||||
|
* called. */
|
||||||
|
|
||||||
|
/** Zero based index for every input and output socket. */
|
||||||
|
int index() const;
|
||||||
|
/** Socket index in the entire node tree. Inputs and outputs share the same index space. */
|
||||||
|
int index_in_tree() const;
|
||||||
|
/** Node this socket belongs to. */
|
||||||
|
bNode &owner_node();
|
||||||
|
const bNode &owner_node() const;
|
||||||
|
/** Node tree this socket belongs to. */
|
||||||
|
const bNodeTree &owner_tree() const;
|
||||||
|
|
||||||
|
/** Links which are incident to this socket. */
|
||||||
|
blender::Span<bNodeLink *> directly_linked_links();
|
||||||
|
blender::Span<const bNodeLink *> directly_linked_links() const;
|
||||||
|
/** Sockets which are connected to this socket with a link. */
|
||||||
|
blender::Span<const bNodeSocket *> directly_linked_sockets() const;
|
||||||
|
bool is_directly_linked() const;
|
||||||
|
/**
|
||||||
|
* Sockets which are connected to this socket when reroutes and muted nodes are taken into
|
||||||
|
* account.
|
||||||
|
*/
|
||||||
|
blender::Span<const bNodeSocket *> logically_linked_sockets() const;
|
||||||
|
bool is_logically_linked() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For output sockets, this is the corresponding input socket the value of which should be
|
||||||
|
* forwarded when the node is muted.
|
||||||
|
*/
|
||||||
|
const bNodeSocket *internal_link_input() const;
|
||||||
|
|
||||||
|
#endif
|
||||||
} bNodeSocket;
|
} bNodeSocket;
|
||||||
|
|
||||||
/** #bNodeSocket.type & #bNodeSocketType.type */
|
/** #bNodeSocket.type & #bNodeSocketType.type */
|
||||||
@@ -333,6 +378,38 @@ typedef struct bNode {
|
|||||||
char iter_flag;
|
char iter_flag;
|
||||||
|
|
||||||
bNodeRuntimeHandle *runtime;
|
bNodeRuntimeHandle *runtime;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
blender::StringRefNull label_or_name() const;
|
||||||
|
bool is_muted() const;
|
||||||
|
bool is_reroute() const;
|
||||||
|
bool is_frame() const;
|
||||||
|
bool is_group() const;
|
||||||
|
bool is_group_input() const;
|
||||||
|
bool is_group_output() const;
|
||||||
|
const blender::nodes::NodeDeclaration *declaration() const;
|
||||||
|
|
||||||
|
/* The following methods are only available when #bNodeTree.ensure_topology_cache has been
|
||||||
|
* called. */
|
||||||
|
|
||||||
|
/** A span containing all input sockets of the node (including unavailable sockets). */
|
||||||
|
blender::Span<bNodeSocket *> input_sockets();
|
||||||
|
blender::Span<const bNodeSocket *> input_sockets() const;
|
||||||
|
/** A span containing all output sockets of the node (including unavailable sockets). */
|
||||||
|
blender::Span<bNodeSocket *> output_sockets();
|
||||||
|
blender::Span<const bNodeSocket *> output_sockets() const;
|
||||||
|
/** Utility to get an input socket by its index. */
|
||||||
|
bNodeSocket &input_socket(int index);
|
||||||
|
const bNodeSocket &input_socket(int index) const;
|
||||||
|
/** Utility to get an output socket by its index. */
|
||||||
|
bNodeSocket &output_socket(int index);
|
||||||
|
const bNodeSocket &output_socket(int index) const;
|
||||||
|
/** A span containing all internal links when the node is muted. */
|
||||||
|
blender::Span<const bNodeLink *> internal_links_span() const;
|
||||||
|
/** Lookup socket of this node by its identifier. */
|
||||||
|
const bNodeSocket &input_by_identifier(blender::StringRef identifier) const;
|
||||||
|
const bNodeSocket &output_by_identifier(blender::StringRef identifier) const;
|
||||||
|
#endif
|
||||||
} bNode;
|
} bNode;
|
||||||
|
|
||||||
/* node->flag */
|
/* node->flag */
|
||||||
@@ -422,6 +499,11 @@ typedef struct bNodeLink {
|
|||||||
|
|
||||||
int flag;
|
int flag;
|
||||||
int multi_input_socket_index;
|
int multi_input_socket_index;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
bool is_muted() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
} bNodeLink;
|
} bNodeLink;
|
||||||
|
|
||||||
/* link->flag */
|
/* link->flag */
|
||||||
@@ -535,6 +617,50 @@ typedef struct bNodeTree {
|
|||||||
struct PreviewImage *preview;
|
struct PreviewImage *preview;
|
||||||
|
|
||||||
bNodeTreeRuntimeHandle *runtime;
|
bNodeTreeRuntimeHandle *runtime;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
/**
|
||||||
|
* Update a run-time cache for the node tree based on it's current state. This makes many methods
|
||||||
|
* available which allow efficient lookup for topology information (like neighboring sockets).
|
||||||
|
*/
|
||||||
|
void ensure_topology_cache() const;
|
||||||
|
|
||||||
|
/* The following methods are only available when #bNodeTree.ensure_topology_cache has been
|
||||||
|
* called. */
|
||||||
|
|
||||||
|
/** A span containing all nodes in the node tree. */
|
||||||
|
blender::Span<bNode *> all_nodes();
|
||||||
|
blender::Span<const bNode *> all_nodes() const;
|
||||||
|
/** A span containing all input sockets in the node tree. */
|
||||||
|
blender::Span<bNodeSocket *> all_input_sockets();
|
||||||
|
blender::Span<const bNodeSocket *> all_input_sockets() const;
|
||||||
|
/** A span containing all output sockets in the node tree. */
|
||||||
|
blender::Span<bNodeSocket *> all_output_sockets();
|
||||||
|
blender::Span<const bNodeSocket *> all_output_sockets() const;
|
||||||
|
/** A span containing all sockets in the node tree. */
|
||||||
|
blender::Span<bNodeSocket *> all_sockets();
|
||||||
|
blender::Span<const bNodeSocket *> all_sockets() const;
|
||||||
|
/** Efficient lookup of all nodes with a specific type. */
|
||||||
|
blender::Span<bNode *> nodes_by_type(blender::StringRefNull type_idname);
|
||||||
|
blender::Span<const bNode *> nodes_by_type(blender::StringRefNull type_idname) const;
|
||||||
|
/**
|
||||||
|
* Cached toposort of all nodes. If there are cycles, the returned array is not actually a
|
||||||
|
* toposort. However, if a connected component does not contain a cycle, this component is sorted
|
||||||
|
* correctly. Use #has_link_cycle to check for cycles.
|
||||||
|
*/
|
||||||
|
blender::Span<const bNode *> toposort_left_to_right() const;
|
||||||
|
blender::Span<const bNode *> toposort_right_to_left() const;
|
||||||
|
/** True when there are any cycles in the node tree. */
|
||||||
|
bool has_link_cycle() const;
|
||||||
|
/**
|
||||||
|
* True when there are nodes or sockets in the node tree that don't use a known type. This can
|
||||||
|
* happen when nodes don't exist in the current Blender version that existed in the version where
|
||||||
|
* this node tree was saved.
|
||||||
|
*/
|
||||||
|
bool has_undefined_nodes_or_sockets() const;
|
||||||
|
/** Get the active group output node. */
|
||||||
|
const bNode *group_output_node() const;
|
||||||
|
#endif
|
||||||
} bNodeTree;
|
} bNodeTree;
|
||||||
|
|
||||||
/** #NodeTree.type, index */
|
/** #NodeTree.type, index */
|
||||||
@@ -2210,7 +2336,3 @@ typedef enum NodeCombSepColorMode {
|
|||||||
NODE_COMBSEP_COLOR_HSV = 1,
|
NODE_COMBSEP_COLOR_HSV = 1,
|
||||||
NODE_COMBSEP_COLOR_HSL = 2,
|
NODE_COMBSEP_COLOR_HSL = 2,
|
||||||
} NodeCombSepColorMode;
|
} NodeCombSepColorMode;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -506,6 +506,54 @@ static short *add_struct(int namecode)
|
|||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copied from `BLI_str_startswith` string.c
|
||||||
|
* to avoid complicating the compilation process of makesdna. */
|
||||||
|
static bool str_startswith(const char *__restrict str, const char *__restrict start)
|
||||||
|
{
|
||||||
|
for (; *str && *start; str++, start++) {
|
||||||
|
if (*str != *start) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*start == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if `str` is a preprocessor string that starts with `start`.
|
||||||
|
* The `start` doesn't need the `#` prefix.
|
||||||
|
* `ifdef VALUE` will match `#ifdef VALUE` as well as `# ifdef VALUE`.
|
||||||
|
*/
|
||||||
|
static bool match_preproc_prefix(const char *__restrict str, const char *__restrict start)
|
||||||
|
{
|
||||||
|
if (*str != '#') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
while (*str == ' ') {
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return str_startswith(str, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \return The point in `str` that starts with `start` or NULL when not found.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static char *match_preproc_strstr(char *__restrict str, const char *__restrict start)
|
||||||
|
{
|
||||||
|
while ((str = strchr(str, '#'))) {
|
||||||
|
str++;
|
||||||
|
while (*str == ' ') {
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
if (str_startswith(str, start)) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int preprocess_include(char *maindata, const int maindata_len)
|
static int preprocess_include(char *maindata, const int maindata_len)
|
||||||
{
|
{
|
||||||
/* NOTE: len + 1, last character is a dummy to prevent
|
/* NOTE: len + 1, last character is a dummy to prevent
|
||||||
@@ -533,6 +581,10 @@ static int preprocess_include(char *maindata, const int maindata_len)
|
|||||||
cp++;
|
cp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* No need for leading '#' character. */
|
||||||
|
const char *cpp_block_start = "ifdef __cplusplus";
|
||||||
|
const char *cpp_block_end = "endif";
|
||||||
|
|
||||||
/* data from temp copy to maindata, remove comments and double spaces */
|
/* data from temp copy to maindata, remove comments and double spaces */
|
||||||
cp = temp;
|
cp = temp;
|
||||||
char *md = maindata;
|
char *md = maindata;
|
||||||
@@ -577,6 +629,18 @@ static int preprocess_include(char *maindata, const int maindata_len)
|
|||||||
skip_until_closing_brace = false;
|
skip_until_closing_brace = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (match_preproc_prefix(cp, cpp_block_start)) {
|
||||||
|
char *end_ptr = match_preproc_strstr(cp, cpp_block_end);
|
||||||
|
|
||||||
|
if (end_ptr == NULL) {
|
||||||
|
fprintf(stderr, "Error: '%s' block must end with '%s'\n", cpp_block_start, cpp_block_end);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const int skip_offset = end_ptr - cp + strlen(cpp_block_end);
|
||||||
|
a -= skip_offset;
|
||||||
|
cp += skip_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
md[0] = cp[0];
|
md[0] = cp[0];
|
||||||
md++;
|
md++;
|
||||||
|
|||||||
@@ -756,18 +756,18 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void initialize_group_input(NodesModifierData &nmd,
|
static void initialize_group_input(NodesModifierData &nmd,
|
||||||
const OutputSocketRef &socket,
|
const bNodeSocket &socket,
|
||||||
void *r_value)
|
void *r_value)
|
||||||
{
|
{
|
||||||
const bNodeSocketType &socket_type = *socket.typeinfo();
|
const bNodeSocketType &socket_type = *socket.typeinfo;
|
||||||
const bNodeSocket &bsocket = *socket.bsocket();
|
const bNodeSocket &bsocket = socket;
|
||||||
const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(bsocket.type);
|
const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(bsocket.type);
|
||||||
if (nmd.settings.properties == nullptr) {
|
if (nmd.settings.properties == nullptr) {
|
||||||
socket_type.get_geometry_nodes_cpp_value(bsocket, r_value);
|
socket_type.get_geometry_nodes_cpp_value(bsocket, r_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties,
|
const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties,
|
||||||
socket.identifier().c_str());
|
socket.identifier);
|
||||||
if (property == nullptr) {
|
if (property == nullptr) {
|
||||||
socket_type.get_geometry_nodes_cpp_value(bsocket, r_value);
|
socket_type.get_geometry_nodes_cpp_value(bsocket, r_value);
|
||||||
return;
|
return;
|
||||||
@@ -777,15 +777,15 @@ static void initialize_group_input(NodesModifierData &nmd,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!input_has_attribute_toggle(*nmd.node_group, socket.index())) {
|
if (!input_has_attribute_toggle(*nmd.node_group, socket.runtime->index_in_node)) {
|
||||||
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
|
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup(
|
const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup(
|
||||||
nmd.settings.properties, (socket.identifier() + use_attribute_suffix).c_str());
|
nmd.settings.properties, (socket.identifier + use_attribute_suffix).c_str());
|
||||||
const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
|
const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
|
||||||
nmd.settings.properties, (socket.identifier() + attribute_name_suffix).c_str());
|
nmd.settings.properties, (socket.identifier + attribute_name_suffix).c_str());
|
||||||
if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
|
if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
|
||||||
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
|
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
|
||||||
return;
|
return;
|
||||||
@@ -867,11 +867,11 @@ static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadshe
|
|||||||
|
|
||||||
const DTreeContext *context = &tree.root_context();
|
const DTreeContext *context = &tree.root_context();
|
||||||
for (SpreadsheetContextNode *node_context : nested_group_contexts) {
|
for (SpreadsheetContextNode *node_context : nested_group_contexts) {
|
||||||
const NodeTreeRef &tree_ref = context->tree();
|
const bNodeTree &btree = context->btree();
|
||||||
const NodeRef *found_node = nullptr;
|
const bNode *found_node = nullptr;
|
||||||
for (const NodeRef *node_ref : tree_ref.nodes()) {
|
for (const bNode *bnode : btree.all_nodes()) {
|
||||||
if (node_ref->name() == node_context->node_name) {
|
if (STREQ(bnode->name, node_context->node_name)) {
|
||||||
found_node = node_ref;
|
found_node = bnode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -884,11 +884,11 @@ static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadshe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const NodeTreeRef &tree_ref = context->tree();
|
const bNodeTree &btree = context->btree();
|
||||||
for (const NodeRef *node_ref : tree_ref.nodes_by_type("GeometryNodeViewer")) {
|
for (const bNode *bnode : btree.nodes_by_type("GeometryNodeViewer")) {
|
||||||
if (node_ref->name() == last_context->node_name) {
|
if (STREQ(bnode->name, last_context->node_name)) {
|
||||||
const DNode viewer_node{context, node_ref};
|
const DNode viewer_node{context, bnode};
|
||||||
for (const InputSocketRef *input_socket : node_ref->inputs()) {
|
for (const bNodeSocket *input_socket : bnode->input_sockets()) {
|
||||||
if (input_socket->is_available() && input_socket->is_logically_linked()) {
|
if (input_socket->is_available() && input_socket->is_logically_linked()) {
|
||||||
r_sockets_to_preview.add(DSocket{context, input_socket});
|
r_sockets_to_preview.add(DSocket{context, input_socket});
|
||||||
}
|
}
|
||||||
@@ -937,15 +937,15 @@ struct OutputAttributeToStore {
|
|||||||
* can be evaluated together.
|
* can be evaluated together.
|
||||||
*/
|
*/
|
||||||
static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to_store(
|
static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to_store(
|
||||||
const NodesModifierData &nmd, const NodeRef &output_node, Span<GMutablePointer> output_values)
|
const NodesModifierData &nmd, const bNode &output_node, Span<GMutablePointer> output_values)
|
||||||
{
|
{
|
||||||
MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain;
|
MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain;
|
||||||
for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) {
|
for (const bNodeSocket *socket : output_node.input_sockets().drop_front(1).drop_back(1)) {
|
||||||
if (!socket_type_has_attribute_toggle(*socket->bsocket())) {
|
if (!socket_type_has_attribute_toggle(*socket)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string prop_name = socket->identifier() + attribute_name_suffix;
|
const std::string prop_name = socket->identifier + attribute_name_suffix;
|
||||||
const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str());
|
const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str());
|
||||||
if (prop == nullptr) {
|
if (prop == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
@@ -965,7 +965,7 @@ static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to
|
|||||||
const GField field = cpp_type->as_field(value.get());
|
const GField field = cpp_type->as_field(value.get());
|
||||||
|
|
||||||
const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(
|
const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(
|
||||||
&nmd.node_group->outputs, socket->index());
|
&nmd.node_group->outputs, index);
|
||||||
const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain;
|
const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain;
|
||||||
OutputAttributeInfo output_info;
|
OutputAttributeInfo output_info;
|
||||||
output_info.field = std::move(field);
|
output_info.field = std::move(field);
|
||||||
@@ -1064,7 +1064,7 @@ static void store_computed_output_attributes(
|
|||||||
|
|
||||||
static void store_output_attributes(GeometrySet &geometry,
|
static void store_output_attributes(GeometrySet &geometry,
|
||||||
const NodesModifierData &nmd,
|
const NodesModifierData &nmd,
|
||||||
const NodeRef &output_node,
|
const bNode &output_node,
|
||||||
Span<GMutablePointer> output_values)
|
Span<GMutablePointer> output_values)
|
||||||
{
|
{
|
||||||
/* All new attribute values have to be computed before the geometry is actually changed. This is
|
/* All new attribute values have to be computed before the geometry is actually changed. This is
|
||||||
@@ -1080,8 +1080,8 @@ static void store_output_attributes(GeometrySet &geometry,
|
|||||||
* Evaluate a node group to compute the output geometry.
|
* Evaluate a node group to compute the output geometry.
|
||||||
*/
|
*/
|
||||||
static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
||||||
Span<const NodeRef *> group_input_nodes,
|
Span<const bNode *> group_input_nodes,
|
||||||
const NodeRef &output_node,
|
const bNode &output_node,
|
||||||
GeometrySet input_geometry_set,
|
GeometrySet input_geometry_set,
|
||||||
NodesModifierData *nmd,
|
NodesModifierData *nmd,
|
||||||
const ModifierEvalContext *ctx)
|
const ModifierEvalContext *ctx)
|
||||||
@@ -1093,18 +1093,19 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
|||||||
Map<DOutputSocket, GMutablePointer> group_inputs;
|
Map<DOutputSocket, GMutablePointer> group_inputs;
|
||||||
|
|
||||||
const DTreeContext *root_context = &tree.root_context();
|
const DTreeContext *root_context = &tree.root_context();
|
||||||
for (const NodeRef *group_input_node : group_input_nodes) {
|
for (const bNode *group_input_node : group_input_nodes) {
|
||||||
Span<const OutputSocketRef *> group_input_sockets = group_input_node->outputs().drop_back(1);
|
Span<const bNodeSocket *> group_input_sockets = group_input_node->output_sockets().drop_back(
|
||||||
|
1);
|
||||||
if (group_input_sockets.is_empty()) {
|
if (group_input_sockets.is_empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets;
|
Span<const bNodeSocket *> remaining_input_sockets = group_input_sockets;
|
||||||
|
|
||||||
/* If the group expects a geometry as first input, use the geometry that has been passed to
|
/* If the group expects a geometry as first input, use the geometry that has been passed to
|
||||||
* modifier. */
|
* modifier. */
|
||||||
const OutputSocketRef *first_input_socket = group_input_sockets[0];
|
const bNodeSocket *first_input_socket = group_input_sockets[0];
|
||||||
if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) {
|
if (first_input_socket->type == SOCK_GEOMETRY) {
|
||||||
GeometrySet *geometry_set_in =
|
GeometrySet *geometry_set_in =
|
||||||
allocator.construct<GeometrySet>(input_geometry_set).release();
|
allocator.construct<GeometrySet>(input_geometry_set).release();
|
||||||
group_inputs.add_new({root_context, first_input_socket}, geometry_set_in);
|
group_inputs.add_new({root_context, first_input_socket}, geometry_set_in);
|
||||||
@@ -1112,8 +1113,8 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize remaining group inputs. */
|
/* Initialize remaining group inputs. */
|
||||||
for (const OutputSocketRef *socket : remaining_input_sockets) {
|
for (const bNodeSocket *socket : remaining_input_sockets) {
|
||||||
const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type;
|
const CPPType &cpp_type = *socket->typeinfo->geometry_nodes_cpp_type;
|
||||||
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
|
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
|
||||||
initialize_group_input(*nmd, *socket, value_in);
|
initialize_group_input(*nmd, *socket, value_in);
|
||||||
group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
|
group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
|
||||||
@@ -1121,7 +1122,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector<DInputSocket> group_outputs;
|
Vector<DInputSocket> group_outputs;
|
||||||
for (const InputSocketRef *socket_ref : output_node.inputs().drop_back(1)) {
|
for (const bNodeSocket *socket_ref : output_node.input_sockets().drop_back(1)) {
|
||||||
group_outputs.append({root_context, socket_ref});
|
group_outputs.append({root_context, socket_ref});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1226,8 +1227,8 @@ static void modifyGeometry(ModifierData *md,
|
|||||||
|
|
||||||
check_property_socket_sync(ctx->object, md);
|
check_property_socket_sync(ctx->object, md);
|
||||||
|
|
||||||
NodeTreeRefMap tree_refs;
|
const bNodeTree &root_tree_ref = *nmd->node_group;
|
||||||
DerivedNodeTree tree{*nmd->node_group, tree_refs};
|
DerivedNodeTree tree{root_tree_ref};
|
||||||
|
|
||||||
if (tree.has_link_cycles()) {
|
if (tree.has_link_cycles()) {
|
||||||
BKE_modifier_set_error(ctx->object, md, "Node group has cycles");
|
BKE_modifier_set_error(ctx->object, md, "Node group has cycles");
|
||||||
@@ -1235,25 +1236,24 @@ static void modifyGeometry(ModifierData *md,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NodeTreeRef &root_tree_ref = tree.root_context().tree();
|
Span<const bNode *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput");
|
||||||
Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput");
|
Span<const bNode *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput");
|
||||||
Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput");
|
|
||||||
if (output_nodes.size() != 1) {
|
if (output_nodes.size() != 1) {
|
||||||
BKE_modifier_set_error(ctx->object, md, "Node group must have a single output node");
|
BKE_modifier_set_error(ctx->object, md, "Node group must have a single output node");
|
||||||
geometry_set.clear();
|
geometry_set.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NodeRef &output_node = *output_nodes[0];
|
const bNode &output_node = *output_nodes[0];
|
||||||
Span<const InputSocketRef *> group_outputs = output_node.inputs().drop_back(1);
|
Span<const bNodeSocket *> group_outputs = output_node.input_sockets().drop_back(1);
|
||||||
if (group_outputs.is_empty()) {
|
if (group_outputs.is_empty()) {
|
||||||
BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket");
|
BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket");
|
||||||
geometry_set.clear();
|
geometry_set.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputSocketRef *first_output_socket = group_outputs[0];
|
const bNodeSocket *first_output_socket = group_outputs[0];
|
||||||
if (first_output_socket->idname() != "NodeSocketGeometry") {
|
if (!STREQ(first_output_socket->idname, "NodeSocketGeometry")) {
|
||||||
BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry");
|
BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry");
|
||||||
geometry_set.clear();
|
geometry_set.clear();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "MOD_nodes_evaluator.hh"
|
#include "MOD_nodes_evaluator.hh"
|
||||||
|
|
||||||
|
#include "BKE_node.h"
|
||||||
#include "BKE_type_conversions.hh"
|
#include "BKE_type_conversions.hh"
|
||||||
|
|
||||||
#include "NOD_geometry_exec.hh"
|
#include "NOD_geometry_exec.hh"
|
||||||
@@ -319,9 +320,9 @@ class LockedNode : NonCopyable, NonMovable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const CPPType *get_socket_cpp_type(const SocketRef &socket)
|
static const CPPType *get_socket_cpp_type(const bNodeSocket &socket)
|
||||||
{
|
{
|
||||||
const bNodeSocketType *typeinfo = socket.typeinfo();
|
const bNodeSocketType *typeinfo = socket.typeinfo;
|
||||||
if (typeinfo->geometry_nodes_cpp_type == nullptr) {
|
if (typeinfo->geometry_nodes_cpp_type == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -338,24 +339,24 @@ static const CPPType *get_socket_cpp_type(const SocketRef &socket)
|
|||||||
|
|
||||||
static const CPPType *get_socket_cpp_type(const DSocket socket)
|
static const CPPType *get_socket_cpp_type(const DSocket socket)
|
||||||
{
|
{
|
||||||
return get_socket_cpp_type(*socket.socket_ref());
|
return get_socket_cpp_type(*socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \note This is not supposed to be a long term solution. Eventually we want that nodes can
|
* \note This is not supposed to be a long term solution. Eventually we want that nodes can
|
||||||
* specify more complex defaults (other than just single values) in their socket declarations.
|
* specify more complex defaults (other than just single values) in their socket declarations.
|
||||||
*/
|
*/
|
||||||
static bool get_implicit_socket_input(const SocketRef &socket, void *r_value)
|
static bool get_implicit_socket_input(const bNodeSocket &socket, void *r_value)
|
||||||
{
|
{
|
||||||
const NodeRef &node = socket.node();
|
const bNode &node = socket.owner_node();
|
||||||
const nodes::NodeDeclaration *node_declaration = node.declaration();
|
const nodes::NodeDeclaration *node_declaration = node.runtime->declaration;
|
||||||
if (node_declaration == nullptr) {
|
if (node_declaration == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const nodes::SocketDeclaration &socket_declaration = *node_declaration->inputs()[socket.index()];
|
const nodes::SocketDeclaration &socket_declaration = *node_declaration->inputs()[socket.index()];
|
||||||
if (socket_declaration.input_field_type() == nodes::InputSocketFieldType::Implicit) {
|
if (socket_declaration.input_field_type() == nodes::InputSocketFieldType::Implicit) {
|
||||||
const bNode &bnode = *socket.bnode();
|
const bNode &bnode = socket.owner_node();
|
||||||
if (socket.typeinfo()->type == SOCK_VECTOR) {
|
if (socket.typeinfo->type == SOCK_VECTOR) {
|
||||||
if (bnode.type == GEO_NODE_SET_CURVE_HANDLES) {
|
if (bnode.type == GEO_NODE_SET_CURVE_HANDLES) {
|
||||||
StringRef side = ((NodeGeometrySetCurveHandlePositions *)bnode.storage)->mode ==
|
StringRef side = ((NodeGeometrySetCurveHandlePositions *)bnode.storage)->mode ==
|
||||||
GEO_NODE_CURVE_HANDLE_LEFT ?
|
GEO_NODE_CURVE_HANDLE_LEFT ?
|
||||||
@@ -372,7 +373,7 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value)
|
|||||||
new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position"));
|
new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (socket.typeinfo()->type == SOCK_INT) {
|
if (socket.typeinfo->type == SOCK_INT) {
|
||||||
if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) {
|
if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) {
|
||||||
new (r_value)
|
new (r_value)
|
||||||
ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>()));
|
ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>()));
|
||||||
@@ -385,19 +386,19 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_socket_value(const SocketRef &socket, void *r_value)
|
static void get_socket_value(const bNodeSocket &socket, void *r_value)
|
||||||
{
|
{
|
||||||
if (get_implicit_socket_input(socket, r_value)) {
|
if (get_implicit_socket_input(socket, r_value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bNodeSocketType *typeinfo = socket.typeinfo();
|
const bNodeSocketType *typeinfo = socket.typeinfo;
|
||||||
typeinfo->get_geometry_nodes_cpp_value(*socket.bsocket(), r_value);
|
typeinfo->get_geometry_nodes_cpp_value(socket, r_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool node_supports_laziness(const DNode node)
|
static bool node_supports_laziness(const DNode node)
|
||||||
{
|
{
|
||||||
return node->typeinfo()->geometry_node_execute_supports_laziness;
|
return node->typeinfo->geometry_node_execute_supports_laziness;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NodeTaskRunState {
|
struct NodeTaskRunState {
|
||||||
@@ -516,9 +517,9 @@ class GeometryNodesEvaluator {
|
|||||||
node_states_.add_new({node, &node_state});
|
node_states_.add_new({node, &node_state});
|
||||||
|
|
||||||
/* Push all linked origins on the stack. */
|
/* Push all linked origins on the stack. */
|
||||||
for (const InputSocketRef *input_ref : node->inputs()) {
|
for (const bNodeSocket *input : node->input_sockets()) {
|
||||||
const DInputSocket input{node.context(), input_ref};
|
const DInputSocket dinput{node.context(), input};
|
||||||
input.foreach_origin_socket(
|
dinput.foreach_origin_socket(
|
||||||
[&](const DSocket origin) { nodes_to_check.push(origin.node()); });
|
[&](const DSocket origin) { nodes_to_check.push(origin.node()); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -546,11 +547,11 @@ class GeometryNodesEvaluator {
|
|||||||
void initialize_node_state(const DNode node, NodeState &node_state, LinearAllocator<> &allocator)
|
void initialize_node_state(const DNode node, NodeState &node_state, LinearAllocator<> &allocator)
|
||||||
{
|
{
|
||||||
/* Construct arrays of the correct size. */
|
/* Construct arrays of the correct size. */
|
||||||
node_state.inputs = allocator.construct_array<InputState>(node->inputs().size());
|
node_state.inputs = allocator.construct_array<InputState>(node->input_sockets().size());
|
||||||
node_state.outputs = allocator.construct_array<OutputState>(node->outputs().size());
|
node_state.outputs = allocator.construct_array<OutputState>(node->output_sockets().size());
|
||||||
|
|
||||||
/* Initialize input states. */
|
/* Initialize input states. */
|
||||||
for (const int i : node->inputs().index_range()) {
|
for (const int i : node->input_sockets().index_range()) {
|
||||||
InputState &input_state = node_state.inputs[i];
|
InputState &input_state = node_state.inputs[i];
|
||||||
const DInputSocket socket = node.input(i);
|
const DInputSocket socket = node.input(i);
|
||||||
if (!socket->is_available()) {
|
if (!socket->is_available()) {
|
||||||
@@ -567,7 +568,7 @@ class GeometryNodesEvaluator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Construct the correct struct that can hold the input(s). */
|
/* Construct the correct struct that can hold the input(s). */
|
||||||
if (socket->is_multi_input_socket()) {
|
if (socket->is_multi_input()) {
|
||||||
input_state.value.multi = allocator.construct<MultiInputValue>().release();
|
input_state.value.multi = allocator.construct<MultiInputValue>().release();
|
||||||
MultiInputValue &multi_value = *input_state.value.multi;
|
MultiInputValue &multi_value = *input_state.value.multi;
|
||||||
/* Count how many values should be added until the socket is complete. */
|
/* Count how many values should be added until the socket is complete. */
|
||||||
@@ -583,7 +584,7 @@ class GeometryNodesEvaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Initialize output states. */
|
/* Initialize output states. */
|
||||||
for (const int i : node->outputs().index_range()) {
|
for (const int i : node->output_sockets().index_range()) {
|
||||||
OutputState &output_state = node_state.outputs[i];
|
OutputState &output_state = node_state.outputs[i];
|
||||||
const DOutputSocket socket = node.output(i);
|
const DOutputSocket socket = node.output(i);
|
||||||
if (!socket->is_available()) {
|
if (!socket->is_available()) {
|
||||||
@@ -629,13 +630,13 @@ class GeometryNodesEvaluator {
|
|||||||
void destruct_node_state(const DNode node, NodeState &node_state)
|
void destruct_node_state(const DNode node, NodeState &node_state)
|
||||||
{
|
{
|
||||||
/* Need to destruct stuff manually, because it's allocated by a custom allocator. */
|
/* Need to destruct stuff manually, because it's allocated by a custom allocator. */
|
||||||
for (const int i : node->inputs().index_range()) {
|
for (const int i : node->input_sockets().index_range()) {
|
||||||
InputState &input_state = node_state.inputs[i];
|
InputState &input_state = node_state.inputs[i];
|
||||||
if (input_state.type == nullptr) {
|
if (input_state.type == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const InputSocketRef &socket_ref = node->input(i);
|
const bNodeSocket &bsocket = node->input_socket(i);
|
||||||
if (socket_ref.is_multi_input_socket()) {
|
if (bsocket.is_multi_input()) {
|
||||||
MultiInputValue &multi_value = *input_state.value.multi;
|
MultiInputValue &multi_value = *input_state.value.multi;
|
||||||
for (void *value : multi_value.values) {
|
for (void *value : multi_value.values) {
|
||||||
if (value != nullptr) {
|
if (value != nullptr) {
|
||||||
@@ -756,7 +757,7 @@ class GeometryNodesEvaluator {
|
|||||||
{
|
{
|
||||||
/* These nodes are sometimes scheduled. We could also check for them in other places, but
|
/* These nodes are sometimes scheduled. We could also check for them in other places, but
|
||||||
* it's the easiest to do it here. */
|
* it's the easiest to do it here. */
|
||||||
if (node->is_group_input_node() || node->is_group_output_node()) {
|
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,7 +838,7 @@ class GeometryNodesEvaluator {
|
|||||||
/* If there are no remaining outputs, all the inputs can be destructed and/or can become
|
/* If there are no remaining outputs, all the inputs can be destructed and/or can become
|
||||||
* unused. This can also trigger a chain reaction where nodes to the left become finished
|
* unused. This can also trigger a chain reaction where nodes to the left become finished
|
||||||
* too. */
|
* too. */
|
||||||
for (const int i : locked_node.node->inputs().index_range()) {
|
for (const int i : locked_node.node->input_sockets().index_range()) {
|
||||||
const DInputSocket socket = locked_node.node.input(i);
|
const DInputSocket socket = locked_node.node.input(i);
|
||||||
InputState &input_state = locked_node.node_state.inputs[i];
|
InputState &input_state = locked_node.node_state.inputs[i];
|
||||||
if (input_state.usage == ValueUsage::Maybe) {
|
if (input_state.usage == ValueUsage::Maybe) {
|
||||||
@@ -883,7 +884,7 @@ class GeometryNodesEvaluator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Nodes that don't support laziness require all inputs. */
|
/* Nodes that don't support laziness require all inputs. */
|
||||||
for (const int i : locked_node.node->inputs().index_range()) {
|
for (const int i : locked_node.node->input_sockets().index_range()) {
|
||||||
InputState &input_state = locked_node.node_state.inputs[i];
|
InputState &input_state = locked_node.node_state.inputs[i];
|
||||||
if (input_state.type == nullptr) {
|
if (input_state.type == nullptr) {
|
||||||
/* Ignore unavailable/non-data sockets. */
|
/* Ignore unavailable/non-data sockets. */
|
||||||
@@ -915,7 +916,7 @@ class GeometryNodesEvaluator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (socket->is_multi_input_socket()) {
|
if (socket->is_multi_input()) {
|
||||||
MultiInputValue &multi_value = *input_state.value.multi;
|
MultiInputValue &multi_value = *input_state.value.multi;
|
||||||
/* Checks if all the linked sockets have been provided already. */
|
/* Checks if all the linked sockets have been provided already. */
|
||||||
if (multi_value.all_values_available()) {
|
if (multi_value.all_values_available()) {
|
||||||
@@ -949,7 +950,7 @@ class GeometryNodesEvaluator {
|
|||||||
*/
|
*/
|
||||||
void execute_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
|
void execute_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
|
||||||
{
|
{
|
||||||
const bNode &bnode = *node->bnode();
|
const bNode &bnode = *node;
|
||||||
|
|
||||||
if (node_state.has_been_executed) {
|
if (node_state.has_been_executed) {
|
||||||
if (!node_supports_laziness(node)) {
|
if (!node_supports_laziness(node)) {
|
||||||
@@ -978,7 +979,7 @@ class GeometryNodesEvaluator {
|
|||||||
void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
|
void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
|
||||||
{
|
{
|
||||||
using Clock = std::chrono::steady_clock;
|
using Clock = std::chrono::steady_clock;
|
||||||
const bNode &bnode = *node->bnode();
|
const bNode &bnode = *node;
|
||||||
|
|
||||||
NodeParamsProvider params_provider{*this, node, node_state, run_state};
|
NodeParamsProvider params_provider{*this, node, node_state, run_state};
|
||||||
GeoNodeExecParams params{params_provider};
|
GeoNodeExecParams params{params_provider};
|
||||||
@@ -1002,12 +1003,12 @@ class GeometryNodesEvaluator {
|
|||||||
bool any_input_is_field = false;
|
bool any_input_is_field = false;
|
||||||
Vector<const void *, 16> input_values;
|
Vector<const void *, 16> input_values;
|
||||||
Vector<const ValueOrFieldCPPType *, 16> input_types;
|
Vector<const ValueOrFieldCPPType *, 16> input_types;
|
||||||
for (const int i : node->inputs().index_range()) {
|
for (const int i : node->input_sockets().index_range()) {
|
||||||
const InputSocketRef &socket_ref = node->input(i);
|
const bNodeSocket &bsocket = node->input_socket(i);
|
||||||
if (!socket_ref.is_available()) {
|
if (!bsocket.is_available()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BLI_assert(!socket_ref.is_multi_input_socket());
|
BLI_assert(!bsocket.is_multi_input());
|
||||||
InputState &input_state = node_state.inputs[i];
|
InputState &input_state = node_state.inputs[i];
|
||||||
BLI_assert(input_state.was_ready_for_execution);
|
BLI_assert(input_state.was_ready_for_execution);
|
||||||
SingleInputValue &single_value = *input_state.value.single;
|
SingleInputValue &single_value = *input_state.value.single;
|
||||||
@@ -1055,15 +1056,15 @@ class GeometryNodesEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int output_index = 0;
|
int output_index = 0;
|
||||||
for (const int i : node->outputs().index_range()) {
|
for (const int i : node->output_sockets().index_range()) {
|
||||||
const OutputSocketRef &socket_ref = node->output(i);
|
const bNodeSocket &bsocket = node->output_socket(i);
|
||||||
if (!socket_ref.is_available()) {
|
if (!bsocket.is_available()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
OutputState &output_state = node_state.outputs[i];
|
OutputState &output_state = node_state.outputs[i];
|
||||||
const DOutputSocket socket{node.context(), &socket_ref};
|
const DOutputSocket socket{node.context(), &bsocket};
|
||||||
const ValueOrFieldCPPType *cpp_type = static_cast<const ValueOrFieldCPPType *>(
|
const ValueOrFieldCPPType *cpp_type = static_cast<const ValueOrFieldCPPType *>(
|
||||||
get_socket_cpp_type(socket_ref));
|
get_socket_cpp_type(bsocket));
|
||||||
GField new_field{operation, output_index};
|
GField new_field{operation, output_index};
|
||||||
void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment());
|
void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment());
|
||||||
cpp_type->construct_from_field(buffer, std::move(new_field));
|
cpp_type->construct_from_field(buffer, std::move(new_field));
|
||||||
@@ -1091,7 +1092,7 @@ class GeometryNodesEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector<GMutablePointer, 16> output_buffers;
|
Vector<GMutablePointer, 16> output_buffers;
|
||||||
for (const int i : node->outputs().index_range()) {
|
for (const int i : node->output_sockets().index_range()) {
|
||||||
const DOutputSocket socket = node.output(i);
|
const DOutputSocket socket = node.output(i);
|
||||||
if (!socket->is_available()) {
|
if (!socket->is_available()) {
|
||||||
output_buffers.append({});
|
output_buffers.append({});
|
||||||
@@ -1128,7 +1129,7 @@ class GeometryNodesEvaluator {
|
|||||||
void execute_unknown_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
|
void execute_unknown_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
|
||||||
{
|
{
|
||||||
LinearAllocator<> &allocator = local_allocators_.local();
|
LinearAllocator<> &allocator = local_allocators_.local();
|
||||||
for (const OutputSocketRef *socket : node->outputs()) {
|
for (const bNodeSocket *socket : node->output_sockets()) {
|
||||||
if (!socket->is_available()) {
|
if (!socket->is_available()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1182,8 +1183,8 @@ class GeometryNodesEvaluator {
|
|||||||
const bool supports_laziness = node_supports_laziness(locked_node.node);
|
const bool supports_laziness = node_supports_laziness(locked_node.node);
|
||||||
/* Iterating over sockets instead of the states directly, because that makes it easier to
|
/* Iterating over sockets instead of the states directly, because that makes it easier to
|
||||||
* figure out which socket is missing when one of the asserts is hit. */
|
* figure out which socket is missing when one of the asserts is hit. */
|
||||||
for (const OutputSocketRef *socket_ref : locked_node.node->outputs()) {
|
for (const bNodeSocket *bsocket : locked_node.node->output_sockets()) {
|
||||||
OutputState &output_state = locked_node.node_state.outputs[socket_ref->index()];
|
OutputState &output_state = locked_node.node_state.outputs[bsocket->index()];
|
||||||
if (supports_laziness) {
|
if (supports_laziness) {
|
||||||
/* Expected that at least all required sockets have been computed. If more outputs become
|
/* Expected that at least all required sockets have been computed. If more outputs become
|
||||||
* required later, the node will be executed again. */
|
* required later, the node will be executed again. */
|
||||||
@@ -1208,7 +1209,7 @@ class GeometryNodesEvaluator {
|
|||||||
{
|
{
|
||||||
for (const DInputSocket &socket : params_.output_sockets) {
|
for (const DInputSocket &socket : params_.output_sockets) {
|
||||||
BLI_assert(socket->is_available());
|
BLI_assert(socket->is_available());
|
||||||
BLI_assert(!socket->is_multi_input_socket());
|
BLI_assert(!socket->is_multi_input());
|
||||||
|
|
||||||
const DNode node = socket.node();
|
const DNode node = socket.node();
|
||||||
NodeState &node_state = this->get_node_state(node);
|
NodeState &node_state = this->get_node_state(node);
|
||||||
@@ -1255,7 +1256,7 @@ class GeometryNodesEvaluator {
|
|||||||
|
|
||||||
/* Count how many values still have to be added to this input until it is "complete". */
|
/* Count how many values still have to be added to this input until it is "complete". */
|
||||||
int missing_values = 0;
|
int missing_values = 0;
|
||||||
if (input_socket->is_multi_input_socket()) {
|
if (input_socket->is_multi_input()) {
|
||||||
MultiInputValue &multi_value = *input_state.value.multi;
|
MultiInputValue &multi_value = *input_state.value.multi;
|
||||||
missing_values = multi_value.missing_values();
|
missing_values = multi_value.missing_values();
|
||||||
}
|
}
|
||||||
@@ -1402,8 +1403,8 @@ class GeometryNodesEvaluator {
|
|||||||
Vector<DInputSocket> forward_original_value_sockets;
|
Vector<DInputSocket> forward_original_value_sockets;
|
||||||
log_original_value_sockets.append(from_socket);
|
log_original_value_sockets.append(from_socket);
|
||||||
|
|
||||||
from_socket.foreach_target_socket(
|
from_socket.foreach_target_socket([&](const DInputSocket to_socket,
|
||||||
[&](const DInputSocket to_socket, const DOutputSocket::TargetSocketPathInfo &path_info) {
|
const DOutputSocket::TargetSocketPathInfo &path_info) {
|
||||||
if (!this->should_forward_to_socket(to_socket)) {
|
if (!this->should_forward_to_socket(to_socket)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1413,9 +1414,8 @@ class GeometryNodesEvaluator {
|
|||||||
const DNode next_node = next_socket.node();
|
const DNode next_node = next_socket.node();
|
||||||
const bool is_last_socket = to_socket == next_socket;
|
const bool is_last_socket = to_socket == next_socket;
|
||||||
const bool do_conversion_if_necessary = is_last_socket ||
|
const bool do_conversion_if_necessary = is_last_socket ||
|
||||||
next_node->is_group_output_node() ||
|
next_node->type == NODE_GROUP_OUTPUT ||
|
||||||
(next_node->is_group_node() &&
|
(next_node->is_group() && !next_node->is_muted());
|
||||||
!next_node->is_muted());
|
|
||||||
if (do_conversion_if_necessary) {
|
if (do_conversion_if_necessary) {
|
||||||
const CPPType &next_type = *get_socket_cpp_type(next_socket);
|
const CPPType &next_type = *get_socket_cpp_type(next_socket);
|
||||||
if (*current_value.type() != next_type) {
|
if (*current_value.type() != next_type) {
|
||||||
@@ -1433,7 +1433,7 @@ class GeometryNodesEvaluator {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Multi-input sockets are logged when all values are available. */
|
/* Multi-input sockets are logged when all values are available. */
|
||||||
if (!(next_socket->is_input() && next_socket->as_input().is_multi_input_socket())) {
|
if (!(next_socket->is_input() && next_socket->is_multi_input())) {
|
||||||
/* Log the converted value at the socket. */
|
/* Log the converted value at the socket. */
|
||||||
this->log_socket_value({next_socket}, current_value);
|
this->log_socket_value({next_socket}, current_value);
|
||||||
}
|
}
|
||||||
@@ -1512,7 +1512,7 @@ class GeometryNodesEvaluator {
|
|||||||
InputState &input_state = node_state.inputs[socket->index()];
|
InputState &input_state = node_state.inputs[socket->index()];
|
||||||
|
|
||||||
this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
|
this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
|
||||||
if (socket->is_multi_input_socket()) {
|
if (socket->is_multi_input()) {
|
||||||
/* Add a new value to the multi-input. */
|
/* Add a new value to the multi-input. */
|
||||||
MultiInputValue &multi_value = *input_state.value.multi;
|
MultiInputValue &multi_value = *input_state.value.multi;
|
||||||
multi_value.add_value(origin, value.get());
|
multi_value.add_value(origin, value.get());
|
||||||
@@ -1555,7 +1555,7 @@ class GeometryNodesEvaluator {
|
|||||||
UNUSED_VARS(locked_node);
|
UNUSED_VARS(locked_node);
|
||||||
|
|
||||||
GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type);
|
GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type);
|
||||||
if (input_socket->is_multi_input_socket()) {
|
if (input_socket->is_multi_input()) {
|
||||||
MultiInputValue &multi_value = *input_state.value.multi;
|
MultiInputValue &multi_value = *input_state.value.multi;
|
||||||
multi_value.add_value(origin_socket, value.get());
|
multi_value.add_value(origin_socket, value.get());
|
||||||
if (multi_value.all_values_available()) {
|
if (multi_value.all_values_available()) {
|
||||||
@@ -1580,7 +1580,7 @@ class GeometryNodesEvaluator {
|
|||||||
void destruct_input_value_if_exists(LockedNode &locked_node, const DInputSocket socket)
|
void destruct_input_value_if_exists(LockedNode &locked_node, const DInputSocket socket)
|
||||||
{
|
{
|
||||||
InputState &input_state = locked_node.node_state.inputs[socket->index()];
|
InputState &input_state = locked_node.node_state.inputs[socket->index()];
|
||||||
if (socket->is_multi_input_socket()) {
|
if (socket->is_multi_input()) {
|
||||||
MultiInputValue &multi_value = *input_state.value.multi;
|
MultiInputValue &multi_value = *input_state.value.multi;
|
||||||
for (void *&value : multi_value.values) {
|
for (void *&value : multi_value.values) {
|
||||||
if (value != nullptr) {
|
if (value != nullptr) {
|
||||||
@@ -1605,7 +1605,7 @@ class GeometryNodesEvaluator {
|
|||||||
|
|
||||||
const CPPType &type = *get_socket_cpp_type(socket);
|
const CPPType &type = *get_socket_cpp_type(socket);
|
||||||
void *buffer = allocator.allocate(type.size(), type.alignment());
|
void *buffer = allocator.allocate(type.size(), type.alignment());
|
||||||
get_socket_value(*socket.socket_ref(), buffer);
|
get_socket_value(*socket.bsocket(), buffer);
|
||||||
|
|
||||||
if (type == required_type) {
|
if (type == required_type) {
|
||||||
return {type, buffer};
|
return {type, buffer};
|
||||||
@@ -1762,7 +1762,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (socket->is_multi_input_socket()) {
|
if (socket->is_multi_input()) {
|
||||||
MultiInputValue &multi_value = *input_state.value.multi;
|
MultiInputValue &multi_value = *input_state.value.multi;
|
||||||
return multi_value.all_values_available();
|
return multi_value.all_values_available();
|
||||||
}
|
}
|
||||||
@@ -1783,7 +1783,7 @@ GMutablePointer NodeParamsProvider::extract_input(StringRef identifier)
|
|||||||
{
|
{
|
||||||
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
|
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
|
||||||
BLI_assert(socket);
|
BLI_assert(socket);
|
||||||
BLI_assert(!socket->is_multi_input_socket());
|
BLI_assert(!socket->is_multi_input());
|
||||||
BLI_assert(this->can_get_input(identifier));
|
BLI_assert(this->can_get_input(identifier));
|
||||||
|
|
||||||
InputState &input_state = node_state_.inputs[socket->index()];
|
InputState &input_state = node_state_.inputs[socket->index()];
|
||||||
@@ -1797,7 +1797,7 @@ Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identi
|
|||||||
{
|
{
|
||||||
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
|
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
|
||||||
BLI_assert(socket);
|
BLI_assert(socket);
|
||||||
BLI_assert(socket->is_multi_input_socket());
|
BLI_assert(socket->is_multi_input());
|
||||||
BLI_assert(this->can_get_input(identifier));
|
BLI_assert(this->can_get_input(identifier));
|
||||||
|
|
||||||
InputState &input_state = node_state_.inputs[socket->index()];
|
InputState &input_state = node_state_.inputs[socket->index()];
|
||||||
@@ -1816,7 +1816,7 @@ GPointer NodeParamsProvider::get_input(StringRef identifier) const
|
|||||||
{
|
{
|
||||||
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
|
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
|
||||||
BLI_assert(socket);
|
BLI_assert(socket);
|
||||||
BLI_assert(!socket->is_multi_input_socket());
|
BLI_assert(!socket->is_multi_input());
|
||||||
BLI_assert(this->can_get_input(identifier));
|
BLI_assert(this->can_get_input(identifier));
|
||||||
|
|
||||||
InputState &input_state = node_state_.inputs[socket->index()];
|
InputState &input_state = node_state_.inputs[socket->index()];
|
||||||
@@ -1901,7 +1901,7 @@ void NodeParamsProvider::set_default_remaining_outputs()
|
|||||||
{
|
{
|
||||||
LinearAllocator<> &allocator = evaluator_.local_allocators_.local();
|
LinearAllocator<> &allocator = evaluator_.local_allocators_.local();
|
||||||
|
|
||||||
for (const int i : this->dnode->outputs().index_range()) {
|
for (const int i : this->dnode->output_sockets().index_range()) {
|
||||||
OutputState &output_state = node_state_.outputs[i];
|
OutputState &output_state = node_state_.outputs[i];
|
||||||
if (output_state.has_been_computed) {
|
if (output_state.has_been_computed) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ set(SRC
|
|||||||
intern/node_multi_function.cc
|
intern/node_multi_function.cc
|
||||||
intern/node_socket.cc
|
intern/node_socket.cc
|
||||||
intern/node_socket_declarations.cc
|
intern/node_socket_declarations.cc
|
||||||
intern/node_tree_ref.cc
|
|
||||||
intern/node_util.c
|
intern/node_util.c
|
||||||
intern/socket_search_link.cc
|
intern/socket_search_link.cc
|
||||||
|
|
||||||
@@ -63,7 +62,6 @@ set(SRC
|
|||||||
NOD_math_functions.hh
|
NOD_math_functions.hh
|
||||||
NOD_multi_function.hh
|
NOD_multi_function.hh
|
||||||
NOD_node_declaration.hh
|
NOD_node_declaration.hh
|
||||||
NOD_node_tree_ref.hh
|
|
||||||
NOD_shader.h
|
NOD_shader.h
|
||||||
NOD_socket.h
|
NOD_socket.h
|
||||||
NOD_socket_declarations.hh
|
NOD_socket_declarations.hh
|
||||||
|
|||||||
@@ -5,16 +5,17 @@
|
|||||||
/** \file
|
/** \file
|
||||||
* \ingroup nodes
|
* \ingroup nodes
|
||||||
*
|
*
|
||||||
* DerivedNodeTree builds on top of NodeTreeRef and makes working with (nested) node groups more
|
* DerivedNodeTree makes working with (nested) node groups more convenient and safe. It does so by
|
||||||
* convenient and safe. It does so by pairing nodes and sockets with a context. The context
|
* pairing nodes and sockets with a context. The context contains information about the current
|
||||||
* contains information about the current "instance" of the node or socket. A node might be
|
* "instance" of the node or socket. A node might be "instanced" multiple times when it is in a
|
||||||
* "instanced" multiple times when it is in a node group that is used multiple times.
|
* node group that is used multiple times.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "BLI_function_ref.hh"
|
#include "BLI_function_ref.hh"
|
||||||
|
#include "BLI_linear_allocator.hh"
|
||||||
#include "BLI_vector_set.hh"
|
#include "BLI_vector_set.hh"
|
||||||
|
|
||||||
#include "NOD_node_tree_ref.hh"
|
#include "BKE_node_runtime.hh"
|
||||||
|
|
||||||
namespace blender::nodes {
|
namespace blender::nodes {
|
||||||
|
|
||||||
@@ -40,20 +41,20 @@ class DTreeContext {
|
|||||||
DTreeContext *parent_context_;
|
DTreeContext *parent_context_;
|
||||||
/* Null when this context is for the root node group. Otherwise it points to the group node in
|
/* Null when this context is for the root node group. Otherwise it points to the group node in
|
||||||
* the parent node group that contains this context. */
|
* the parent node group that contains this context. */
|
||||||
const NodeRef *parent_node_;
|
const bNode *parent_node_;
|
||||||
/* The current node tree. */
|
/* The current node tree. */
|
||||||
const NodeTreeRef *tree_;
|
const bNodeTree *btree_;
|
||||||
/* All the children contexts of this context. */
|
/* All the children contexts of this context. */
|
||||||
Map<const NodeRef *, DTreeContext *> children_;
|
Map<const bNode *, DTreeContext *> children_;
|
||||||
DerivedNodeTree *derived_tree_;
|
DerivedNodeTree *derived_tree_;
|
||||||
|
|
||||||
friend DerivedNodeTree;
|
friend DerivedNodeTree;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const NodeTreeRef &tree() const;
|
const bNodeTree &btree() const;
|
||||||
const DTreeContext *parent_context() const;
|
const DTreeContext *parent_context() const;
|
||||||
const NodeRef *parent_node() const;
|
const bNode *parent_node() const;
|
||||||
const DTreeContext *child_context(const NodeRef &node) const;
|
const DTreeContext *child_context(const bNode &node) const;
|
||||||
const DerivedNodeTree &derived_tree() const;
|
const DerivedNodeTree &derived_tree() const;
|
||||||
bool is_root() const;
|
bool is_root() const;
|
||||||
};
|
};
|
||||||
@@ -65,15 +66,16 @@ class DTreeContext {
|
|||||||
class DNode {
|
class DNode {
|
||||||
private:
|
private:
|
||||||
const DTreeContext *context_ = nullptr;
|
const DTreeContext *context_ = nullptr;
|
||||||
const NodeRef *node_ref_ = nullptr;
|
const bNode *bnode_ = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DNode() = default;
|
DNode() = default;
|
||||||
DNode(const DTreeContext *context, const NodeRef *node);
|
DNode(const DTreeContext *context, const bNode *node);
|
||||||
|
|
||||||
const DTreeContext *context() const;
|
const DTreeContext *context() const;
|
||||||
const NodeRef *node_ref() const;
|
const bNode *bnode() const;
|
||||||
const NodeRef *operator->() const;
|
const bNode *operator->() const;
|
||||||
|
const bNode &operator*() const;
|
||||||
|
|
||||||
friend bool operator==(const DNode &a, const DNode &b);
|
friend bool operator==(const DNode &a, const DNode &b);
|
||||||
friend bool operator!=(const DNode &a, const DNode &b);
|
friend bool operator!=(const DNode &a, const DNode &b);
|
||||||
@@ -98,17 +100,18 @@ class DNode {
|
|||||||
class DSocket {
|
class DSocket {
|
||||||
protected:
|
protected:
|
||||||
const DTreeContext *context_ = nullptr;
|
const DTreeContext *context_ = nullptr;
|
||||||
const SocketRef *socket_ref_ = nullptr;
|
const bNodeSocket *bsocket_ = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DSocket() = default;
|
DSocket() = default;
|
||||||
DSocket(const DTreeContext *context, const SocketRef *socket);
|
DSocket(const DTreeContext *context, const bNodeSocket *socket);
|
||||||
DSocket(const DInputSocket &input_socket);
|
DSocket(const DInputSocket &input_socket);
|
||||||
DSocket(const DOutputSocket &output_socket);
|
DSocket(const DOutputSocket &output_socket);
|
||||||
|
|
||||||
const DTreeContext *context() const;
|
const DTreeContext *context() const;
|
||||||
const SocketRef *socket_ref() const;
|
const bNodeSocket *bsocket() const;
|
||||||
const SocketRef *operator->() const;
|
const bNodeSocket *operator->() const;
|
||||||
|
const bNodeSocket &operator*() const;
|
||||||
|
|
||||||
friend bool operator==(const DSocket &a, const DSocket &b);
|
friend bool operator==(const DSocket &a, const DSocket &b);
|
||||||
friend bool operator!=(const DSocket &a, const DSocket &b);
|
friend bool operator!=(const DSocket &a, const DSocket &b);
|
||||||
@@ -123,12 +126,9 @@ class DSocket {
|
|||||||
class DInputSocket : public DSocket {
|
class DInputSocket : public DSocket {
|
||||||
public:
|
public:
|
||||||
DInputSocket() = default;
|
DInputSocket() = default;
|
||||||
DInputSocket(const DTreeContext *context, const InputSocketRef *socket);
|
DInputSocket(const DTreeContext *context, const bNodeSocket *socket);
|
||||||
explicit DInputSocket(const DSocket &base_socket);
|
explicit DInputSocket(const DSocket &base_socket);
|
||||||
|
|
||||||
const InputSocketRef *socket_ref() const;
|
|
||||||
const InputSocketRef *operator->() const;
|
|
||||||
|
|
||||||
DOutputSocket get_corresponding_group_node_output() const;
|
DOutputSocket get_corresponding_group_node_output() const;
|
||||||
Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const;
|
Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const;
|
||||||
|
|
||||||
@@ -144,12 +144,9 @@ class DInputSocket : public DSocket {
|
|||||||
class DOutputSocket : public DSocket {
|
class DOutputSocket : public DSocket {
|
||||||
public:
|
public:
|
||||||
DOutputSocket() = default;
|
DOutputSocket() = default;
|
||||||
DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket);
|
DOutputSocket(const DTreeContext *context, const bNodeSocket *socket);
|
||||||
explicit DOutputSocket(const DSocket &base_socket);
|
explicit DOutputSocket(const DSocket &base_socket);
|
||||||
|
|
||||||
const OutputSocketRef *socket_ref() const;
|
|
||||||
const OutputSocketRef *operator->() const;
|
|
||||||
|
|
||||||
DInputSocket get_corresponding_group_node_input() const;
|
DInputSocket get_corresponding_group_node_input() const;
|
||||||
DInputSocket get_active_corresponding_group_output_socket() const;
|
DInputSocket get_active_corresponding_group_output_socket() const;
|
||||||
|
|
||||||
@@ -177,7 +174,7 @@ class DerivedNodeTree {
|
|||||||
private:
|
private:
|
||||||
LinearAllocator<> allocator_;
|
LinearAllocator<> allocator_;
|
||||||
DTreeContext *root_context_;
|
DTreeContext *root_context_;
|
||||||
VectorSet<const NodeTreeRef *> used_node_tree_refs_;
|
VectorSet<const bNodeTree *> used_btrees_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -186,11 +183,11 @@ class DerivedNodeTree {
|
|||||||
* has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
|
* has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
|
||||||
* derived node tree.
|
* derived node tree.
|
||||||
*/
|
*/
|
||||||
DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs);
|
DerivedNodeTree(const bNodeTree &btree);
|
||||||
~DerivedNodeTree();
|
~DerivedNodeTree();
|
||||||
|
|
||||||
const DTreeContext &root_context() const;
|
const DTreeContext &root_context() const;
|
||||||
Span<const NodeTreeRef *> used_node_tree_refs() const;
|
Span<const bNodeTree *> used_btrees() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \return True when there is a link cycle. Unavailable sockets are ignored.
|
* \return True when there is a link cycle. Unavailable sockets are ignored.
|
||||||
@@ -205,9 +202,8 @@ class DerivedNodeTree {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
DTreeContext &construct_context_recursively(DTreeContext *parent_context,
|
DTreeContext &construct_context_recursively(DTreeContext *parent_context,
|
||||||
const NodeRef *parent_node,
|
const bNode *parent_node,
|
||||||
bNodeTree &btree,
|
const bNodeTree &btree);
|
||||||
NodeTreeRefMap &node_tree_refs);
|
|
||||||
void destruct_context_recursively(DTreeContext *context);
|
void destruct_context_recursively(DTreeContext *context);
|
||||||
|
|
||||||
void foreach_node_in_context_recursive(const DTreeContext &context,
|
void foreach_node_in_context_recursive(const DTreeContext &context,
|
||||||
@@ -215,7 +211,6 @@ class DerivedNodeTree {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace derived_node_tree_types {
|
namespace derived_node_tree_types {
|
||||||
using namespace node_tree_ref_types;
|
|
||||||
using nodes::DerivedNodeTree;
|
using nodes::DerivedNodeTree;
|
||||||
using nodes::DInputSocket;
|
using nodes::DInputSocket;
|
||||||
using nodes::DNode;
|
using nodes::DNode;
|
||||||
@@ -228,9 +223,9 @@ using nodes::DTreeContext;
|
|||||||
/** \name #DTreeContext Inline Methods
|
/** \name #DTreeContext Inline Methods
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
inline const NodeTreeRef &DTreeContext::tree() const
|
inline const bNodeTree &DTreeContext::btree() const
|
||||||
{
|
{
|
||||||
return *tree_;
|
return *btree_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const DTreeContext *DTreeContext::parent_context() const
|
inline const DTreeContext *DTreeContext::parent_context() const
|
||||||
@@ -238,12 +233,12 @@ inline const DTreeContext *DTreeContext::parent_context() const
|
|||||||
return parent_context_;
|
return parent_context_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const NodeRef *DTreeContext::parent_node() const
|
inline const bNode *DTreeContext::parent_node() const
|
||||||
{
|
{
|
||||||
return parent_node_;
|
return parent_node_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const
|
inline const DTreeContext *DTreeContext::child_context(const bNode &node) const
|
||||||
{
|
{
|
||||||
return children_.lookup_default(&node, nullptr);
|
return children_.lookup_default(&node, nullptr);
|
||||||
}
|
}
|
||||||
@@ -264,10 +259,10 @@ inline bool DTreeContext::is_root() const
|
|||||||
/** \name #DNode Inline Methods
|
/** \name #DNode Inline Methods
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref)
|
inline DNode::DNode(const DTreeContext *context, const bNode *bnode)
|
||||||
: context_(context), node_ref_(node_ref)
|
: context_(context), bnode_(bnode)
|
||||||
{
|
{
|
||||||
BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree());
|
BLI_assert(bnode == nullptr || bnode->runtime->owner_tree == &context->btree());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const DTreeContext *DNode::context() const
|
inline const DTreeContext *DNode::context() const
|
||||||
@@ -275,14 +270,14 @@ inline const DTreeContext *DNode::context() const
|
|||||||
return context_;
|
return context_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const NodeRef *DNode::node_ref() const
|
inline const bNode *DNode::bnode() const
|
||||||
{
|
{
|
||||||
return node_ref_;
|
return bnode_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const DNode &a, const DNode &b)
|
inline bool operator==(const DNode &a, const DNode &b)
|
||||||
{
|
{
|
||||||
return a.context_ == b.context_ && a.node_ref_ == b.node_ref_;
|
return a.context_ == b.context_ && a.bnode_ == b.bnode_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!=(const DNode &a, const DNode &b)
|
inline bool operator!=(const DNode &a, const DNode &b)
|
||||||
@@ -292,37 +287,43 @@ inline bool operator!=(const DNode &a, const DNode &b)
|
|||||||
|
|
||||||
inline DNode::operator bool() const
|
inline DNode::operator bool() const
|
||||||
{
|
{
|
||||||
return node_ref_ != nullptr;
|
return bnode_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const NodeRef *DNode::operator->() const
|
inline const bNode *DNode::operator->() const
|
||||||
{
|
{
|
||||||
return node_ref_;
|
return bnode_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNode &DNode::operator*() const
|
||||||
|
{
|
||||||
|
BLI_assert(bnode_ != nullptr);
|
||||||
|
return *bnode_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t DNode::hash() const
|
inline uint64_t DNode::hash() const
|
||||||
{
|
{
|
||||||
return get_default_hash_2(context_, node_ref_);
|
return get_default_hash_2(context_, bnode_);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DInputSocket DNode::input(int index) const
|
inline DInputSocket DNode::input(int index) const
|
||||||
{
|
{
|
||||||
return {context_, &node_ref_->input(index)};
|
return {context_, &bnode_->input_socket(index)};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DOutputSocket DNode::output(int index) const
|
inline DOutputSocket DNode::output(int index) const
|
||||||
{
|
{
|
||||||
return {context_, &node_ref_->output(index)};
|
return {context_, &bnode_->output_socket(index)};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DInputSocket DNode::input_by_identifier(StringRef identifier) const
|
inline DInputSocket DNode::input_by_identifier(StringRef identifier) const
|
||||||
{
|
{
|
||||||
return {context_, &node_ref_->input_by_identifier(identifier)};
|
return {context_, &bnode_->input_by_identifier(identifier)};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const
|
inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const
|
||||||
{
|
{
|
||||||
return {context_, &node_ref_->output_by_identifier(identifier)};
|
return {context_, &bnode_->output_by_identifier(identifier)};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
@@ -331,19 +332,20 @@ inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const
|
|||||||
/** \name #DSocket Inline Methods
|
/** \name #DSocket Inline Methods
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref)
|
inline DSocket::DSocket(const DTreeContext *context, const bNodeSocket *bsocket)
|
||||||
: context_(context), socket_ref_(socket_ref)
|
: context_(context), bsocket_(bsocket)
|
||||||
{
|
{
|
||||||
BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree());
|
BLI_assert(bsocket == nullptr ||
|
||||||
|
bsocket->runtime->owner_node->runtime->owner_tree == &context->btree());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DSocket::DSocket(const DInputSocket &input_socket)
|
inline DSocket::DSocket(const DInputSocket &input_socket)
|
||||||
: DSocket(input_socket.context_, input_socket.socket_ref_)
|
: DSocket(input_socket.context_, input_socket.bsocket_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DSocket::DSocket(const DOutputSocket &output_socket)
|
inline DSocket::DSocket(const DOutputSocket &output_socket)
|
||||||
: DSocket(output_socket.context_, output_socket.socket_ref_)
|
: DSocket(output_socket.context_, output_socket.bsocket_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,14 +354,14 @@ inline const DTreeContext *DSocket::context() const
|
|||||||
return context_;
|
return context_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const SocketRef *DSocket::socket_ref() const
|
inline const bNodeSocket *DSocket::bsocket() const
|
||||||
{
|
{
|
||||||
return socket_ref_;
|
return bsocket_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const DSocket &a, const DSocket &b)
|
inline bool operator==(const DSocket &a, const DSocket &b)
|
||||||
{
|
{
|
||||||
return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_;
|
return a.context_ == b.context_ && a.bsocket_ == b.bsocket_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!=(const DSocket &a, const DSocket &b)
|
inline bool operator!=(const DSocket &a, const DSocket &b)
|
||||||
@@ -369,23 +371,29 @@ inline bool operator!=(const DSocket &a, const DSocket &b)
|
|||||||
|
|
||||||
inline DSocket::operator bool() const
|
inline DSocket::operator bool() const
|
||||||
{
|
{
|
||||||
return socket_ref_ != nullptr;
|
return bsocket_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const SocketRef *DSocket::operator->() const
|
inline const bNodeSocket *DSocket::operator->() const
|
||||||
{
|
{
|
||||||
return socket_ref_;
|
return bsocket_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const bNodeSocket &DSocket::operator*() const
|
||||||
|
{
|
||||||
|
BLI_assert(bsocket_ != nullptr);
|
||||||
|
return *bsocket_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t DSocket::hash() const
|
inline uint64_t DSocket::hash() const
|
||||||
{
|
{
|
||||||
return get_default_hash_2(context_, socket_ref_);
|
return get_default_hash_2(context_, bsocket_);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DNode DSocket::node() const
|
inline DNode DSocket::node() const
|
||||||
{
|
{
|
||||||
BLI_assert(socket_ref_ != nullptr);
|
BLI_assert(bsocket_ != nullptr);
|
||||||
return {context_, &socket_ref_->node()};
|
return {context_, bsocket_->runtime->owner_node};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
@@ -394,8 +402,8 @@ inline DNode DSocket::node() const
|
|||||||
/** \name #DInputSocket Inline Methods
|
/** \name #DInputSocket Inline Methods
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref)
|
inline DInputSocket::DInputSocket(const DTreeContext *context, const bNodeSocket *bsocket)
|
||||||
: DSocket(context, socket_ref)
|
: DSocket(context, bsocket)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,24 +412,14 @@ inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_soc
|
|||||||
BLI_assert(base_socket->is_input());
|
BLI_assert(base_socket->is_input());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const InputSocketRef *DInputSocket::socket_ref() const
|
|
||||||
{
|
|
||||||
return (const InputSocketRef *)socket_ref_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const InputSocketRef *DInputSocket::operator->() const
|
|
||||||
{
|
|
||||||
return (const InputSocketRef *)socket_ref_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name #DOutputSocket Inline Methods
|
/** \name #DOutputSocket Inline Methods
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref)
|
inline DOutputSocket::DOutputSocket(const DTreeContext *context, const bNodeSocket *bsocket)
|
||||||
: DSocket(context, socket_ref)
|
: DSocket(context, bsocket)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,16 +428,6 @@ inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_s
|
|||||||
BLI_assert(base_socket->is_output());
|
BLI_assert(base_socket->is_output());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const OutputSocketRef *DOutputSocket::socket_ref() const
|
|
||||||
{
|
|
||||||
return (const OutputSocketRef *)socket_ref_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const OutputSocketRef *DOutputSocket::operator->() const
|
|
||||||
{
|
|
||||||
return (const OutputSocketRef *)socket_ref_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
@@ -451,9 +439,9 @@ inline const DTreeContext &DerivedNodeTree::root_context() const
|
|||||||
return *root_context_;
|
return *root_context_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Span<const NodeTreeRef *> DerivedNodeTree::used_node_tree_refs() const
|
inline Span<const bNodeTree *> DerivedNodeTree::used_btrees() const
|
||||||
{
|
{
|
||||||
return used_node_tree_refs_;
|
return used_btrees_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ class GeoNodeExecParams {
|
|||||||
*/
|
*/
|
||||||
const bNode &node() const
|
const bNode &node() const
|
||||||
{
|
{
|
||||||
return *provider_->dnode->bnode();
|
return *provider_->dnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Object *self_object() const
|
const Object *self_object() const
|
||||||
|
|||||||
@@ -19,15 +19,15 @@ class NodeMultiFunctions;
|
|||||||
*/
|
*/
|
||||||
class NodeMultiFunctionBuilder : NonCopyable, NonMovable {
|
class NodeMultiFunctionBuilder : NonCopyable, NonMovable {
|
||||||
private:
|
private:
|
||||||
bNode &node_;
|
const bNode &node_;
|
||||||
bNodeTree &tree_;
|
const bNodeTree &tree_;
|
||||||
std::shared_ptr<MultiFunction> owned_built_fn_;
|
std::shared_ptr<MultiFunction> owned_built_fn_;
|
||||||
const MultiFunction *built_fn_ = nullptr;
|
const MultiFunction *built_fn_ = nullptr;
|
||||||
|
|
||||||
friend NodeMultiFunctions;
|
friend NodeMultiFunctions;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree);
|
NodeMultiFunctionBuilder(const bNode &node, const bNodeTree &tree);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign a multi-function for the current node. The input and output parameters of the function
|
* Assign a multi-function for the current node. The input and output parameters of the function
|
||||||
@@ -42,8 +42,8 @@ class NodeMultiFunctionBuilder : NonCopyable, NonMovable {
|
|||||||
*/
|
*/
|
||||||
template<typename T, typename... Args> void construct_and_set_matching_fn(Args &&...args);
|
template<typename T, typename... Args> void construct_and_set_matching_fn(Args &&...args);
|
||||||
|
|
||||||
bNode &node();
|
const bNode &node();
|
||||||
bNodeTree &tree();
|
const bNodeTree &tree();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,17 +69,17 @@ class NodeMultiFunctions {
|
|||||||
/** \name #NodeMultiFunctionBuilder Inline Methods
|
/** \name #NodeMultiFunctionBuilder Inline Methods
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree)
|
inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(const bNode &node, const bNodeTree &tree)
|
||||||
: node_(node), tree_(tree)
|
: node_(node), tree_(tree)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bNode &NodeMultiFunctionBuilder::node()
|
inline const bNode &NodeMultiFunctionBuilder::node()
|
||||||
{
|
{
|
||||||
return node_;
|
return node_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bNodeTree &NodeMultiFunctionBuilder::tree()
|
inline const bNodeTree &NodeMultiFunctionBuilder::tree()
|
||||||
{
|
{
|
||||||
return tree_;
|
return tree_;
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@ inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...ar
|
|||||||
inline const NodeMultiFunctions::Item &NodeMultiFunctions::try_get(const DNode &node) const
|
inline const NodeMultiFunctions::Item &NodeMultiFunctions::try_get(const DNode &node) const
|
||||||
{
|
{
|
||||||
static Item empty_item;
|
static Item empty_item;
|
||||||
const Item *item = map_.lookup_ptr(node->bnode());
|
const Item *item = map_.lookup_ptr(node.bnode());
|
||||||
if (item == nullptr) {
|
if (item == nullptr) {
|
||||||
return empty_item;
|
return empty_item;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,760 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
#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 -> directly linked links
|
|
||||||
* - 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_function_ref.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 "BKE_node_runtime.hh"
|
|
||||||
|
|
||||||
#include "DNA_node_types.h"
|
|
||||||
|
|
||||||
#include "RNA_access.h"
|
|
||||||
|
|
||||||
namespace blender::nodes {
|
|
||||||
|
|
||||||
class SocketRef;
|
|
||||||
class InputSocketRef;
|
|
||||||
class OutputSocketRef;
|
|
||||||
class NodeRef;
|
|
||||||
class NodeTreeRef;
|
|
||||||
class LinkRef;
|
|
||||||
class InternalLinkRef;
|
|
||||||
|
|
||||||
using SocketIndexByIdentifierMap = Map<std::string, int>;
|
|
||||||
|
|
||||||
class SocketRef : NonCopyable, NonMovable {
|
|
||||||
protected:
|
|
||||||
NodeRef *node_;
|
|
||||||
bNodeSocket *bsocket_;
|
|
||||||
bool is_input_;
|
|
||||||
int id_;
|
|
||||||
int index_;
|
|
||||||
Vector<LinkRef *> directly_linked_links_;
|
|
||||||
|
|
||||||
/* These sockets are linked directly, i.e. with a single link in between. */
|
|
||||||
MutableSpan<const SocketRef *> directly_linked_sockets_;
|
|
||||||
/* These sockets are linked when reroutes, muted links and muted nodes have been taken into
|
|
||||||
* account. */
|
|
||||||
MutableSpan<const SocketRef *> logically_linked_sockets_;
|
|
||||||
/* These are the sockets that have been skipped when searching for logically linked sockets.
|
|
||||||
* That includes for example the input and output socket of an intermediate reroute node. */
|
|
||||||
MutableSpan<const SocketRef *> logically_linked_skipped_sockets_;
|
|
||||||
|
|
||||||
friend NodeTreeRef;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Span<const SocketRef *> logically_linked_sockets() const;
|
|
||||||
Span<const SocketRef *> logically_linked_skipped_sockets() const;
|
|
||||||
Span<const SocketRef *> directly_linked_sockets() const;
|
|
||||||
Span<const LinkRef *> directly_linked_links() const;
|
|
||||||
|
|
||||||
bool is_directly_linked() const;
|
|
||||||
bool is_logically_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;
|
|
||||||
StringRefNull identifier() const;
|
|
||||||
bNodeSocketType *typeinfo() const;
|
|
||||||
|
|
||||||
bNodeSocket *bsocket() const;
|
|
||||||
bNode *bnode() const;
|
|
||||||
bNodeTree *btree() const;
|
|
||||||
|
|
||||||
bool is_available() const;
|
|
||||||
bool is_undefined() const;
|
|
||||||
|
|
||||||
void *default_value() const;
|
|
||||||
template<typename T> T *default_value() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class InputSocketRef final : public SocketRef {
|
|
||||||
public:
|
|
||||||
friend NodeTreeRef;
|
|
||||||
|
|
||||||
Span<const OutputSocketRef *> logically_linked_sockets() const;
|
|
||||||
Span<const OutputSocketRef *> directly_linked_sockets() const;
|
|
||||||
|
|
||||||
bool is_multi_input_socket() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void foreach_logical_origin(FunctionRef<void(const OutputSocketRef &)> origin_fn,
|
|
||||||
FunctionRef<void(const SocketRef &)> skipped_fn,
|
|
||||||
bool only_follow_first_input_link,
|
|
||||||
Vector<const InputSocketRef *> &seen_sockets_stack) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class OutputSocketRef final : public SocketRef {
|
|
||||||
public:
|
|
||||||
friend NodeTreeRef;
|
|
||||||
|
|
||||||
Span<const InputSocketRef *> logically_linked_sockets() const;
|
|
||||||
Span<const InputSocketRef *> directly_linked_sockets() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void foreach_logical_target(FunctionRef<void(const InputSocketRef &)> target_fn,
|
|
||||||
FunctionRef<void(const SocketRef &)> skipped_fn,
|
|
||||||
Vector<const OutputSocketRef *> &seen_sockets_stack) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NodeRef : NonCopyable, NonMovable {
|
|
||||||
private:
|
|
||||||
NodeTreeRef *tree_;
|
|
||||||
bNode *bnode_;
|
|
||||||
int id_;
|
|
||||||
Vector<InputSocketRef *> inputs_;
|
|
||||||
Vector<OutputSocketRef *> outputs_;
|
|
||||||
Vector<InternalLinkRef *> internal_links_;
|
|
||||||
SocketIndexByIdentifierMap *input_index_by_identifier_;
|
|
||||||
SocketIndexByIdentifierMap *output_index_by_identifier_;
|
|
||||||
|
|
||||||
friend NodeTreeRef;
|
|
||||||
|
|
||||||
public:
|
|
||||||
const NodeTreeRef &tree() const;
|
|
||||||
|
|
||||||
Span<const InputSocketRef *> inputs() const;
|
|
||||||
Span<const OutputSocketRef *> outputs() const;
|
|
||||||
Span<const InternalLinkRef *> internal_links() const;
|
|
||||||
Span<const SocketRef *> sockets(eNodeSocketInOut in_out) const;
|
|
||||||
|
|
||||||
const InputSocketRef &input(int index) const;
|
|
||||||
const OutputSocketRef &output(int index) const;
|
|
||||||
|
|
||||||
const InputSocketRef &input_by_identifier(StringRef identifier) const;
|
|
||||||
const OutputSocketRef &output_by_identifier(StringRef identifier) const;
|
|
||||||
|
|
||||||
bool any_input_is_directly_linked() const;
|
|
||||||
bool any_output_is_directly_linked() const;
|
|
||||||
bool any_socket_is_directly_linked(eNodeSocketInOut in_out) const;
|
|
||||||
|
|
||||||
bNode *bnode() const;
|
|
||||||
bNodeTree *btree() const;
|
|
||||||
|
|
||||||
PointerRNA rna() const;
|
|
||||||
StringRefNull idname() const;
|
|
||||||
StringRefNull name() const;
|
|
||||||
StringRefNull label() const;
|
|
||||||
StringRefNull label_or_name() const;
|
|
||||||
bNodeType *typeinfo() const;
|
|
||||||
const NodeDeclaration *declaration() 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;
|
|
||||||
bool is_frame() const;
|
|
||||||
bool is_undefined() const;
|
|
||||||
|
|
||||||
void *storage() const;
|
|
||||||
template<typename T> T *storage() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LinkRef : NonCopyable, NonMovable {
|
|
||||||
private:
|
|
||||||
OutputSocketRef *from_;
|
|
||||||
InputSocketRef *to_;
|
|
||||||
bNodeLink *blink_;
|
|
||||||
|
|
||||||
friend NodeTreeRef;
|
|
||||||
|
|
||||||
public:
|
|
||||||
const OutputSocketRef &from() const;
|
|
||||||
const InputSocketRef &to() const;
|
|
||||||
|
|
||||||
bNodeLink *blink() const;
|
|
||||||
|
|
||||||
bool is_muted() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class InternalLinkRef : NonCopyable, NonMovable {
|
|
||||||
private:
|
|
||||||
InputSocketRef *from_;
|
|
||||||
OutputSocketRef *to_;
|
|
||||||
bNodeLink *blink_;
|
|
||||||
|
|
||||||
friend NodeTreeRef;
|
|
||||||
|
|
||||||
public:
|
|
||||||
const InputSocketRef &from() const;
|
|
||||||
const OutputSocketRef &to() const;
|
|
||||||
|
|
||||||
bNodeLink *blink() 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_;
|
|
||||||
Vector<LinkRef *> links_;
|
|
||||||
MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_;
|
|
||||||
Vector<std::unique_ptr<SocketIndexByIdentifierMap>> owned_identifier_maps_;
|
|
||||||
const NodeRef *group_output_node_ = nullptr;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
Span<const LinkRef *> links() const;
|
|
||||||
|
|
||||||
const NodeRef *find_node(const bNode &bnode) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the active group output node if there are multiple.
|
|
||||||
*/
|
|
||||||
const NodeRef *group_output_node() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \return True when there is a link cycle. Unavailable sockets are ignored.
|
|
||||||
*/
|
|
||||||
bool has_link_cycles() const;
|
|
||||||
bool has_undefined_nodes_or_sockets() const;
|
|
||||||
|
|
||||||
enum class ToposortDirection {
|
|
||||||
LeftToRight,
|
|
||||||
RightToLeft,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ToposortResult {
|
|
||||||
Vector<const NodeRef *> sorted_nodes;
|
|
||||||
/**
|
|
||||||
* There can't be a correct topological sort of the nodes when there is a cycle. The nodes will
|
|
||||||
* still be sorted to some degree. The caller has to decide whether it can handle non-perfect
|
|
||||||
* sorts or not.
|
|
||||||
*/
|
|
||||||
bool has_cycle = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort nodes topologically from left to right or right to left.
|
|
||||||
* In the future the result if this could be cached on #NodeTreeRef.
|
|
||||||
*/
|
|
||||||
ToposortResult toposort(ToposortDirection direction) const;
|
|
||||||
|
|
||||||
bNodeTree *btree() const;
|
|
||||||
StringRefNull name() 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 create_linked_socket_caches();
|
|
||||||
void create_socket_identifier_maps();
|
|
||||||
};
|
|
||||||
|
|
||||||
using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>;
|
|
||||||
|
|
||||||
const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree);
|
|
||||||
|
|
||||||
namespace node_tree_ref_types {
|
|
||||||
using nodes::InputSocketRef;
|
|
||||||
using nodes::NodeRef;
|
|
||||||
using nodes::NodeTreeRef;
|
|
||||||
using nodes::NodeTreeRefMap;
|
|
||||||
using nodes::OutputSocketRef;
|
|
||||||
using nodes::SocketRef;
|
|
||||||
} // namespace node_tree_ref_types
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name #SocketRef Inline Methods
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
inline Span<const SocketRef *> SocketRef::logically_linked_sockets() const
|
|
||||||
{
|
|
||||||
return logically_linked_sockets_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Span<const SocketRef *> SocketRef::logically_linked_skipped_sockets() const
|
|
||||||
{
|
|
||||||
return logically_linked_skipped_sockets_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Span<const SocketRef *> SocketRef::directly_linked_sockets() const
|
|
||||||
{
|
|
||||||
return directly_linked_sockets_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Span<const LinkRef *> SocketRef::directly_linked_links() const
|
|
||||||
{
|
|
||||||
return directly_linked_links_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool SocketRef::is_directly_linked() const
|
|
||||||
{
|
|
||||||
return directly_linked_sockets_.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool SocketRef::is_logically_linked() const
|
|
||||||
{
|
|
||||||
return logically_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 StringRefNull SocketRef::idname() const
|
|
||||||
{
|
|
||||||
return bsocket_->idname;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline StringRefNull SocketRef::name() const
|
|
||||||
{
|
|
||||||
return bsocket_->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline StringRefNull SocketRef::identifier() const
|
|
||||||
{
|
|
||||||
return bsocket_->identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNodeSocketType *SocketRef::typeinfo() const
|
|
||||||
{
|
|
||||||
return bsocket_->typeinfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNodeSocket *SocketRef::bsocket() const
|
|
||||||
{
|
|
||||||
return bsocket_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNode *SocketRef::bnode() const
|
|
||||||
{
|
|
||||||
return node_->bnode();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNodeTree *SocketRef::btree() const
|
|
||||||
{
|
|
||||||
return node_->btree();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool SocketRef::is_available() const
|
|
||||||
{
|
|
||||||
return (bsocket_->flag & SOCK_UNAVAIL) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool SocketRef::is_undefined() const
|
|
||||||
{
|
|
||||||
return bsocket_->typeinfo == &NodeSocketTypeUndefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void *SocketRef::default_value() const
|
|
||||||
{
|
|
||||||
return bsocket_->default_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> inline T *SocketRef::default_value() const
|
|
||||||
{
|
|
||||||
return (T *)bsocket_->default_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name #InputSocketRef Inline Methods
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
inline Span<const OutputSocketRef *> InputSocketRef::logically_linked_sockets() const
|
|
||||||
{
|
|
||||||
return logically_linked_sockets_.as_span().cast<const OutputSocketRef *>();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Span<const OutputSocketRef *> InputSocketRef::directly_linked_sockets() const
|
|
||||||
{
|
|
||||||
return directly_linked_sockets_.cast<const OutputSocketRef *>();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool InputSocketRef::is_multi_input_socket() const
|
|
||||||
{
|
|
||||||
return bsocket_->flag & SOCK_MULTI_INPUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name #OutputSocketRef Inline Methods
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
inline Span<const InputSocketRef *> OutputSocketRef::logically_linked_sockets() const
|
|
||||||
{
|
|
||||||
return logically_linked_sockets_.as_span().cast<const InputSocketRef *>();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Span<const InputSocketRef *> OutputSocketRef::directly_linked_sockets() const
|
|
||||||
{
|
|
||||||
return directly_linked_sockets_.cast<const InputSocketRef *>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name #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 Span<const SocketRef *> NodeRef::sockets(const eNodeSocketInOut in_out) const
|
|
||||||
{
|
|
||||||
return in_out == SOCK_IN ? inputs_.as_span().cast<const SocketRef *>() :
|
|
||||||
outputs_.as_span().cast<const SocketRef *>();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Span<const InternalLinkRef *> NodeRef::internal_links() const
|
|
||||||
{
|
|
||||||
return internal_links_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const InputSocketRef &NodeRef::input(int index) const
|
|
||||||
{
|
|
||||||
return *inputs_[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const OutputSocketRef &NodeRef::output(int index) const
|
|
||||||
{
|
|
||||||
return *outputs_[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const InputSocketRef &NodeRef::input_by_identifier(StringRef identifier) const
|
|
||||||
{
|
|
||||||
const int index = input_index_by_identifier_->lookup_as(identifier);
|
|
||||||
return this->input(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const OutputSocketRef &NodeRef::output_by_identifier(StringRef identifier) const
|
|
||||||
{
|
|
||||||
const int index = output_index_by_identifier_->lookup_as(identifier);
|
|
||||||
return this->output(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNode *NodeRef::bnode() const
|
|
||||||
{
|
|
||||||
return bnode_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNodeTree *NodeRef::btree() const
|
|
||||||
{
|
|
||||||
return tree_->btree();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline StringRefNull NodeRef::idname() const
|
|
||||||
{
|
|
||||||
return bnode_->idname;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline StringRefNull NodeRef::name() const
|
|
||||||
{
|
|
||||||
return bnode_->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline StringRefNull NodeRef::label() const
|
|
||||||
{
|
|
||||||
return bnode_->label;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline StringRefNull NodeRef::label_or_name() const
|
|
||||||
{
|
|
||||||
const StringRefNull label = this->label();
|
|
||||||
if (!label.is_empty()) {
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
return this->name();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNodeType *NodeRef::typeinfo() const
|
|
||||||
{
|
|
||||||
return bnode_->typeinfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns a pointer because not all nodes have declarations currently. */
|
|
||||||
inline const NodeDeclaration *NodeRef::declaration() const
|
|
||||||
{
|
|
||||||
nodeDeclarationEnsure(this->tree().btree(), bnode_);
|
|
||||||
return bnode_->runtime->declaration;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 || bnode_->type == NODE_CUSTOM_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_frame() const
|
|
||||||
{
|
|
||||||
return bnode_->type == NODE_FRAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool NodeRef::is_undefined() const
|
|
||||||
{
|
|
||||||
return bnode_->typeinfo == &NodeTypeUndefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool NodeRef::is_muted() const
|
|
||||||
{
|
|
||||||
return (bnode_->flag & NODE_MUTED) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void *NodeRef::storage() const
|
|
||||||
{
|
|
||||||
return bnode_->storage;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> inline T *NodeRef::storage() const
|
|
||||||
{
|
|
||||||
return (T *)bnode_->storage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name #LinkRef Inline Methods
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
inline const OutputSocketRef &LinkRef::from() const
|
|
||||||
{
|
|
||||||
return *from_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const InputSocketRef &LinkRef::to() const
|
|
||||||
{
|
|
||||||
return *to_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNodeLink *LinkRef::blink() const
|
|
||||||
{
|
|
||||||
return blink_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool LinkRef::is_muted() const
|
|
||||||
{
|
|
||||||
return blink_->flag & NODE_LINK_MUTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name #InternalLinkRef Inline Methods
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
inline const InputSocketRef &InternalLinkRef::from() const
|
|
||||||
{
|
|
||||||
return *from_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const OutputSocketRef &InternalLinkRef::to() const
|
|
||||||
{
|
|
||||||
return *to_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNodeLink *InternalLinkRef::blink() const
|
|
||||||
{
|
|
||||||
return blink_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name #NodeTreeRef 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 Span<const LinkRef *> NodeTreeRef::links() const
|
|
||||||
{
|
|
||||||
return links_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const NodeRef *NodeTreeRef::group_output_node() const
|
|
||||||
{
|
|
||||||
return group_output_node_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bNodeTree *NodeTreeRef::btree() const
|
|
||||||
{
|
|
||||||
return btree_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline StringRefNull NodeTreeRef::name() const
|
|
||||||
{
|
|
||||||
return btree_->id.name + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
} // namespace blender::nodes
|
|
||||||
@@ -457,8 +457,8 @@ class ImageOperation : public NodeOperation {
|
|||||||
|
|
||||||
update_image_frame_number();
|
update_image_frame_number();
|
||||||
|
|
||||||
for (const OutputSocketRef *output : node()->outputs()) {
|
for (const bNodeSocket *output : this->node()->output_sockets()) {
|
||||||
compute_output(output->identifier());
|
compute_output(output->identifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,12 +488,12 @@ class ImageOperation : public NodeOperation {
|
|||||||
/* Allocate all needed outputs as invalid. This should be called when is_valid returns false. */
|
/* Allocate all needed outputs as invalid. This should be called when is_valid returns false. */
|
||||||
void allocate_invalid()
|
void allocate_invalid()
|
||||||
{
|
{
|
||||||
for (const OutputSocketRef *output : node()->outputs()) {
|
for (const bNodeSocket *output : this->node()->output_sockets()) {
|
||||||
if (!should_compute_output(output->identifier())) {
|
if (!should_compute_output(output->identifier)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result &result = get_result(output->identifier());
|
Result &result = get_result(output->identifier);
|
||||||
result.allocate_invalid();
|
result.allocate_invalid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -594,7 +594,7 @@ class ImageOperation : public NodeOperation {
|
|||||||
const char *get_pass_name(StringRef identifier)
|
const char *get_pass_name(StringRef identifier)
|
||||||
{
|
{
|
||||||
DOutputSocket output = node().output_by_identifier(identifier);
|
DOutputSocket output = node().output_by_identifier(identifier);
|
||||||
return static_cast<NodeImageLayer *>(output->bsocket()->storage)->pass_name;
|
return static_cast<NodeImageLayer *>(output->storage)->pass_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the index of the pass with the given name in the selected render layer's passes list
|
/* Get the index of the pass with the given name in the selected render layer's passes list
|
||||||
@@ -850,9 +850,9 @@ class RenderLayerOperation : public NodeOperation {
|
|||||||
alpha_result.unbind_as_image();
|
alpha_result.unbind_as_image();
|
||||||
|
|
||||||
/* Other output passes are not supported for now, so allocate them as invalid. */
|
/* Other output passes are not supported for now, so allocate them as invalid. */
|
||||||
for (const OutputSocketRef *output : node()->outputs()) {
|
for (const bNodeSocket *output : this->node()->output_sockets()) {
|
||||||
if (output->identifier() != "Image" && output->identifier() != "Alpha") {
|
if (!STREQ(output->identifier, "Image") && !STREQ(output->identifier, "Alpha")) {
|
||||||
get_result(output->identifier()).allocate_invalid();
|
get_result(output->identifier).allocate_invalid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,9 +51,12 @@ class NormalShaderNode : public ShaderNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* The vector value is stored in the default value of the output socket. */
|
/* The vector value is stored in the default value of the output socket. */
|
||||||
float *get_vector_value()
|
const float *get_vector_value()
|
||||||
{
|
{
|
||||||
return node().output_by_identifier("Normal")->default_value<bNodeSocketValueVector>()->value;
|
return node()
|
||||||
|
.output_by_identifier("Normal")
|
||||||
|
->default_value_typed<bNodeSocketValueVector>()
|
||||||
|
->value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,4 +23,6 @@
|
|||||||
|
|
||||||
#include "FN_multi_function_builder.hh"
|
#include "FN_multi_function_builder.hh"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
|
||||||
void fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
|
void fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ class MF_AlignEulerToVector : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void fn_node_align_euler_to_vector_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void fn_node_align_euler_to_vector_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &node = builder.node();
|
const bNode &node = builder.node();
|
||||||
builder.construct_and_set_matching_fn<MF_AlignEulerToVector>(node.custom1, node.custom2);
|
builder.construct_and_set_matching_fn<MF_AlignEulerToVector>(node.custom1, node.custom2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const fn::MultiFunction *get_multi_function(bNode &bnode)
|
static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
||||||
{
|
{
|
||||||
static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle();
|
static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle();
|
||||||
static fn::CustomMF_SI_SI_SO<bool, bool, bool> and_fn{
|
static fn::CustomMF_SI_SI_SO<bool, bool, bool> and_fn{
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ static void fn_node_combine_color_init(bNodeTree *UNUSED(tree), bNode *node)
|
|||||||
node->storage = data;
|
node->storage = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const fn::MultiFunction *get_multi_function(bNode &bnode)
|
static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
||||||
{
|
{
|
||||||
const NodeCombSepColor &storage = node_storage(bnode);
|
const NodeCombSepColor &storage = node_storage(bnode);
|
||||||
|
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ static float component_average(float3 a)
|
|||||||
return (a.x + a.y + a.z) / 3.0f;
|
return (a.x + a.y + a.z) / 3.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const fn::MultiFunction *get_multi_function(bNode &node)
|
static const fn::MultiFunction *get_multi_function(const bNode &node)
|
||||||
{
|
{
|
||||||
const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage;
|
const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage;
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ static void node_float_to_int_label(const bNodeTree *UNUSED(ntree),
|
|||||||
BLI_strncpy(label, IFACE_(name), maxlen);
|
BLI_strncpy(label, IFACE_(name), maxlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const fn::MultiFunction *get_multi_function(bNode &bnode)
|
static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
||||||
{
|
{
|
||||||
static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle();
|
static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle();
|
||||||
static fn::CustomMF_SI_SO<float, int> round_fn{
|
static fn::CustomMF_SI_SO<float, int> round_fn{
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ static void fn_node_input_bool_layout(uiLayout *layout, bContext *UNUSED(C), Poi
|
|||||||
|
|
||||||
static void fn_node_input_bool_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void fn_node_input_bool_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &bnode = builder.node();
|
const bNode &bnode = builder.node();
|
||||||
NodeInputBool *node_storage = static_cast<NodeInputBool *>(bnode.storage);
|
NodeInputBool *node_storage = static_cast<NodeInputBool *>(bnode.storage);
|
||||||
builder.construct_and_set_matching_fn<fn::CustomMF_Constant<bool>>(node_storage->boolean);
|
builder.construct_and_set_matching_fn<fn::CustomMF_Constant<bool>>(node_storage->boolean);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ static void fn_node_input_color_layout(uiLayout *layout, bContext *UNUSED(C), Po
|
|||||||
static void fn_node_input_color_build_multi_function(
|
static void fn_node_input_color_build_multi_function(
|
||||||
blender::nodes::NodeMultiFunctionBuilder &builder)
|
blender::nodes::NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &bnode = builder.node();
|
const bNode &bnode = builder.node();
|
||||||
NodeInputColor *node_storage = static_cast<NodeInputColor *>(bnode.storage);
|
NodeInputColor *node_storage = static_cast<NodeInputColor *>(bnode.storage);
|
||||||
blender::ColorGeometry4f color = (ColorGeometry4f)node_storage->color;
|
blender::ColorGeometry4f color = (ColorGeometry4f)node_storage->color;
|
||||||
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<ColorGeometry4f>>(color);
|
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<ColorGeometry4f>>(color);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ static void fn_node_input_int_layout(uiLayout *layout, bContext *UNUSED(C), Poin
|
|||||||
|
|
||||||
static void fn_node_input_int_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void fn_node_input_int_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &bnode = builder.node();
|
const bNode &bnode = builder.node();
|
||||||
NodeInputInt *node_storage = static_cast<NodeInputInt *>(bnode.storage);
|
NodeInputInt *node_storage = static_cast<NodeInputInt *>(bnode.storage);
|
||||||
builder.construct_and_set_matching_fn<fn::CustomMF_Constant<int>>(node_storage->integer);
|
builder.construct_and_set_matching_fn<fn::CustomMF_Constant<int>>(node_storage->integer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ static void fn_node_input_string_layout(uiLayout *layout, bContext *UNUSED(C), P
|
|||||||
|
|
||||||
static void fn_node_input_string_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void fn_node_input_string_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &bnode = builder.node();
|
const bNode &bnode = builder.node();
|
||||||
NodeInputString *node_storage = static_cast<NodeInputString *>(bnode.storage);
|
NodeInputString *node_storage = static_cast<NodeInputString *>(bnode.storage);
|
||||||
std::string string = std::string((node_storage->string) ? node_storage->string : "");
|
std::string string = std::string((node_storage->string) ? node_storage->string : "");
|
||||||
builder.construct_and_set_matching_fn<fn::CustomMF_Constant<std::string>>(std::move(string));
|
builder.construct_and_set_matching_fn<fn::CustomMF_Constant<std::string>>(std::move(string));
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), P
|
|||||||
|
|
||||||
static void fn_node_input_vector_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void fn_node_input_vector_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &bnode = builder.node();
|
const bNode &bnode = builder.node();
|
||||||
NodeInputVector *node_storage = static_cast<NodeInputVector *>(bnode.storage);
|
NodeInputVector *node_storage = static_cast<NodeInputVector *>(bnode.storage);
|
||||||
float3 vector(node_storage->vector);
|
float3 vector(node_storage->vector);
|
||||||
builder.construct_and_set_matching_fn<fn::CustomMF_Constant<float3>>(vector);
|
builder.construct_and_set_matching_fn<fn::CustomMF_Constant<float3>>(vector);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), P
|
|||||||
uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
|
uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const fn::MultiFunction *get_multi_function(bNode &bnode)
|
static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
||||||
{
|
{
|
||||||
static fn::CustomMF_SI_SI_SO<float3, float3, float3> obj_euler_rot{
|
static fn::CustomMF_SI_SI_SO<float3, float3, float3> obj_euler_rot{
|
||||||
"Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) {
|
"Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) {
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#include "NOD_socket_declarations.hh"
|
#include "NOD_socket_declarations.hh"
|
||||||
#include "NOD_socket_declarations_geometry.hh"
|
#include "NOD_socket_declarations_geometry.hh"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
|
||||||
#include "node_util.h"
|
#include "node_util.h"
|
||||||
|
|
||||||
void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
|
void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
|
||||||
|
|||||||
@@ -2,38 +2,38 @@
|
|||||||
|
|
||||||
#include "NOD_derived_node_tree.hh"
|
#include "NOD_derived_node_tree.hh"
|
||||||
|
|
||||||
|
#include "BKE_node.h"
|
||||||
|
|
||||||
#include "BLI_dot_export.hh"
|
#include "BLI_dot_export.hh"
|
||||||
|
|
||||||
namespace blender::nodes {
|
namespace blender::nodes {
|
||||||
|
|
||||||
DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs)
|
DerivedNodeTree::DerivedNodeTree(const bNodeTree &btree)
|
||||||
{
|
{
|
||||||
/* Construct all possible contexts immediately. This is significantly cheaper than inlining all
|
/* 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
|
* node groups. If it still becomes a performance issue in the future, contexts could be
|
||||||
* constructed lazily when they are needed. */
|
* constructed lazily when they are needed. */
|
||||||
root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs);
|
root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree);
|
||||||
}
|
}
|
||||||
|
|
||||||
DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context,
|
DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context,
|
||||||
const NodeRef *parent_node,
|
const bNode *parent_node,
|
||||||
bNodeTree &btree,
|
const bNodeTree &btree)
|
||||||
NodeTreeRefMap &node_tree_refs)
|
|
||||||
{
|
{
|
||||||
|
btree.ensure_topology_cache();
|
||||||
DTreeContext &context = *allocator_.construct<DTreeContext>().release();
|
DTreeContext &context = *allocator_.construct<DTreeContext>().release();
|
||||||
context.parent_context_ = parent_context;
|
context.parent_context_ = parent_context;
|
||||||
context.parent_node_ = parent_node;
|
context.parent_node_ = parent_node;
|
||||||
context.derived_tree_ = this;
|
context.derived_tree_ = this;
|
||||||
context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree);
|
context.btree_ = &btree;
|
||||||
used_node_tree_refs_.add(context.tree_);
|
used_btrees_.add(context.btree_);
|
||||||
|
|
||||||
for (const NodeRef *node : context.tree_->nodes()) {
|
for (const bNode *bnode : context.btree_->all_nodes()) {
|
||||||
if (node->is_group_node()) {
|
if (bnode->is_group()) {
|
||||||
bNode *bnode = node->bnode();
|
|
||||||
bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id);
|
bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id);
|
||||||
if (child_btree != nullptr) {
|
if (child_btree != nullptr) {
|
||||||
DTreeContext &child = this->construct_context_recursively(
|
DTreeContext &child = this->construct_context_recursively(&context, bnode, *child_btree);
|
||||||
&context, node, *child_btree, node_tree_refs);
|
context.children_.add_new(bnode, &child);
|
||||||
context.children_.add_new(node, &child);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,8 +57,8 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
|
|||||||
|
|
||||||
bool DerivedNodeTree::has_link_cycles() const
|
bool DerivedNodeTree::has_link_cycles() const
|
||||||
{
|
{
|
||||||
for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
|
for (const bNodeTree *btree : used_btrees_) {
|
||||||
if (tree_ref->has_link_cycles()) {
|
if (btree->has_link_cycle()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,8 +67,8 @@ bool DerivedNodeTree::has_link_cycles() const
|
|||||||
|
|
||||||
bool DerivedNodeTree::has_undefined_nodes_or_sockets() const
|
bool DerivedNodeTree::has_undefined_nodes_or_sockets() const
|
||||||
{
|
{
|
||||||
for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
|
for (const bNodeTree *btree : used_btrees_) {
|
||||||
if (tree_ref->has_undefined_nodes_or_sockets()) {
|
if (btree->has_undefined_nodes_or_sockets()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,8 +83,8 @@ void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const
|
|||||||
void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context,
|
void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context,
|
||||||
FunctionRef<void(DNode)> callback) const
|
FunctionRef<void(DNode)> callback) const
|
||||||
{
|
{
|
||||||
for (const NodeRef *node_ref : context.tree_->nodes()) {
|
for (const bNode *bnode : context.btree_->all_nodes()) {
|
||||||
callback(DNode(&context, node_ref));
|
callback(DNode(&context, bnode));
|
||||||
}
|
}
|
||||||
for (const DTreeContext *child_context : context.children_.values()) {
|
for (const DTreeContext *child_context : context.children_.values()) {
|
||||||
this->foreach_node_in_context_recursive(*child_context, callback);
|
this->foreach_node_in_context_recursive(*child_context, callback);
|
||||||
@@ -94,32 +94,32 @@ void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &cont
|
|||||||
DOutputSocket DInputSocket::get_corresponding_group_node_output() const
|
DOutputSocket DInputSocket::get_corresponding_group_node_output() const
|
||||||
{
|
{
|
||||||
BLI_assert(*this);
|
BLI_assert(*this);
|
||||||
BLI_assert(socket_ref_->node().is_group_output_node());
|
BLI_assert(bsocket_->owner_node().is_group_output());
|
||||||
BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1);
|
BLI_assert(bsocket_->index() < bsocket_->owner_node().input_sockets().size() - 1);
|
||||||
|
|
||||||
const DTreeContext *parent_context = context_->parent_context();
|
const DTreeContext *parent_context = context_->parent_context();
|
||||||
const NodeRef *parent_node = context_->parent_node();
|
const bNode *parent_node = context_->parent_node();
|
||||||
BLI_assert(parent_context != nullptr);
|
BLI_assert(parent_context != nullptr);
|
||||||
BLI_assert(parent_node != nullptr);
|
BLI_assert(parent_node != nullptr);
|
||||||
|
|
||||||
const int socket_index = socket_ref_->index();
|
const int socket_index = bsocket_->index();
|
||||||
return {parent_context, &parent_node->output(socket_index)};
|
return {parent_context, &parent_node->output_socket(socket_index)};
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() const
|
Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() const
|
||||||
{
|
{
|
||||||
BLI_assert(*this);
|
BLI_assert(*this);
|
||||||
BLI_assert(socket_ref_->node().is_group_node());
|
BLI_assert(bsocket_->owner_node().is_group());
|
||||||
|
|
||||||
const DTreeContext *child_context = context_->child_context(socket_ref_->node());
|
const DTreeContext *child_context = context_->child_context(bsocket_->owner_node());
|
||||||
BLI_assert(child_context != nullptr);
|
BLI_assert(child_context != nullptr);
|
||||||
|
|
||||||
const NodeTreeRef &child_tree = child_context->tree();
|
const bNodeTree &child_tree = child_context->btree();
|
||||||
Span<const NodeRef *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput");
|
Span<const bNode *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput");
|
||||||
const int socket_index = socket_ref_->index();
|
const int socket_index = bsocket_->index();
|
||||||
Vector<DOutputSocket> sockets;
|
Vector<DOutputSocket> sockets;
|
||||||
for (const NodeRef *group_input_node : group_input_nodes) {
|
for (const bNode *group_input_node : group_input_nodes) {
|
||||||
sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index)));
|
sockets.append(DOutputSocket(child_context, &group_input_node->output_socket(socket_index)));
|
||||||
}
|
}
|
||||||
return sockets;
|
return sockets;
|
||||||
}
|
}
|
||||||
@@ -127,36 +127,36 @@ Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() cons
|
|||||||
DInputSocket DOutputSocket::get_corresponding_group_node_input() const
|
DInputSocket DOutputSocket::get_corresponding_group_node_input() const
|
||||||
{
|
{
|
||||||
BLI_assert(*this);
|
BLI_assert(*this);
|
||||||
BLI_assert(socket_ref_->node().is_group_input_node());
|
BLI_assert(bsocket_->owner_node().is_group_input());
|
||||||
BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1);
|
BLI_assert(bsocket_->index() < bsocket_->owner_node().output_sockets().size() - 1);
|
||||||
|
|
||||||
const DTreeContext *parent_context = context_->parent_context();
|
const DTreeContext *parent_context = context_->parent_context();
|
||||||
const NodeRef *parent_node = context_->parent_node();
|
const bNode *parent_node = context_->parent_node();
|
||||||
BLI_assert(parent_context != nullptr);
|
BLI_assert(parent_context != nullptr);
|
||||||
BLI_assert(parent_node != nullptr);
|
BLI_assert(parent_node != nullptr);
|
||||||
|
|
||||||
const int socket_index = socket_ref_->index();
|
const int socket_index = bsocket_->index();
|
||||||
return {parent_context, &parent_node->input(socket_index)};
|
return {parent_context, &parent_node->input_socket(socket_index)};
|
||||||
}
|
}
|
||||||
|
|
||||||
DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
|
DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
|
||||||
{
|
{
|
||||||
BLI_assert(*this);
|
BLI_assert(*this);
|
||||||
BLI_assert(socket_ref_->node().is_group_node());
|
BLI_assert(bsocket_->owner_node().is_group());
|
||||||
|
|
||||||
const DTreeContext *child_context = context_->child_context(socket_ref_->node());
|
const DTreeContext *child_context = context_->child_context(bsocket_->owner_node());
|
||||||
if (child_context == nullptr) {
|
if (child_context == nullptr) {
|
||||||
/* Can happen when the group node references a non-existent group (e.g. when the group is
|
/* Can happen when the group node references a non-existent group (e.g. when the group is
|
||||||
* linked but the original file is not found). */
|
* linked but the original file is not found). */
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const NodeTreeRef &child_tree = child_context->tree();
|
const bNodeTree &child_tree = child_context->btree();
|
||||||
Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput");
|
Span<const bNode *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput");
|
||||||
const int socket_index = socket_ref_->index();
|
const int socket_index = bsocket_->index();
|
||||||
for (const NodeRef *group_output_node : group_output_nodes) {
|
for (const bNode *group_output_node : group_output_nodes) {
|
||||||
if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) {
|
if (group_output_node->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) {
|
||||||
return {child_context, &group_output_node->input(socket_index)};
|
return {child_context, &group_output_node->input_socket(socket_index)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
@@ -165,11 +165,11 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
|
|||||||
void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const
|
void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const
|
||||||
{
|
{
|
||||||
BLI_assert(*this);
|
BLI_assert(*this);
|
||||||
for (const OutputSocketRef *linked_socket : socket_ref_->as_input().logically_linked_sockets()) {
|
for (const bNodeSocket *linked_socket : bsocket_->logically_linked_sockets()) {
|
||||||
const NodeRef &linked_node = linked_socket->node();
|
const bNode &linked_node = linked_socket->owner_node();
|
||||||
DOutputSocket linked_dsocket{context_, linked_socket};
|
DOutputSocket linked_dsocket{context_, linked_socket};
|
||||||
|
|
||||||
if (linked_node.is_group_input_node()) {
|
if (linked_node.is_group_input()) {
|
||||||
if (context_->is_root()) {
|
if (context_->is_root()) {
|
||||||
/* This is a group input in the root node group. */
|
/* This is a group input in the root node group. */
|
||||||
origin_fn(linked_dsocket);
|
origin_fn(linked_dsocket);
|
||||||
@@ -187,7 +187,7 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (linked_node.is_group_node()) {
|
else if (linked_node.is_group()) {
|
||||||
DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket();
|
DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket();
|
||||||
if (socket_in_group) {
|
if (socket_in_group) {
|
||||||
if (socket_in_group->is_logically_linked()) {
|
if (socket_in_group->is_logically_linked()) {
|
||||||
@@ -217,16 +217,16 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const
|
|||||||
void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
|
void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
|
||||||
TargetSocketPathInfo &path_info) const
|
TargetSocketPathInfo &path_info) const
|
||||||
{
|
{
|
||||||
for (const LinkRef *link : socket_ref_->as_output().directly_linked_links()) {
|
for (const bNodeLink *link : bsocket_->directly_linked_links()) {
|
||||||
if (link->is_muted()) {
|
if (link->is_muted()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const DInputSocket &linked_socket{context_, &link->to()};
|
const DInputSocket &linked_socket{context_, link->tosock};
|
||||||
if (!linked_socket->is_available()) {
|
if (!linked_socket->is_available()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const DNode linked_node = linked_socket.node();
|
const DNode linked_node = linked_socket.node();
|
||||||
if (linked_node->is_reroute_node()) {
|
if (linked_node->is_reroute()) {
|
||||||
const DInputSocket reroute_input = linked_socket;
|
const DInputSocket reroute_input = linked_socket;
|
||||||
const DOutputSocket reroute_output = linked_node.output(0);
|
const DOutputSocket reroute_output = linked_node.output(0);
|
||||||
path_info.sockets.append(reroute_input);
|
path_info.sockets.append(reroute_input);
|
||||||
@@ -236,18 +236,18 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
|
|||||||
path_info.sockets.pop_last();
|
path_info.sockets.pop_last();
|
||||||
}
|
}
|
||||||
else if (linked_node->is_muted()) {
|
else if (linked_node->is_muted()) {
|
||||||
for (const InternalLinkRef *internal_link : linked_node->internal_links()) {
|
for (const bNodeLink *internal_link : linked_node->internal_links_span()) {
|
||||||
if (&internal_link->from() != linked_socket.socket_ref()) {
|
if (internal_link->fromsock != linked_socket.bsocket()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* The internal link only forwards the first incoming link. */
|
/* The internal link only forwards the first incoming link. */
|
||||||
if (linked_socket->is_multi_input_socket()) {
|
if (linked_socket->is_multi_input()) {
|
||||||
if (linked_socket->directly_linked_links()[0] != link) {
|
if (linked_socket->directly_linked_links()[0] != link) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const DInputSocket mute_input = linked_socket;
|
const DInputSocket mute_input = linked_socket;
|
||||||
const DOutputSocket mute_output{context_, &internal_link->to()};
|
const DOutputSocket mute_output{context_, internal_link->tosock};
|
||||||
path_info.sockets.append(mute_input);
|
path_info.sockets.append(mute_input);
|
||||||
path_info.sockets.append(mute_output);
|
path_info.sockets.append(mute_output);
|
||||||
mute_output.foreach_target_socket(target_fn, path_info);
|
mute_output.foreach_target_socket(target_fn, path_info);
|
||||||
@@ -255,8 +255,8 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
|
|||||||
path_info.sockets.pop_last();
|
path_info.sockets.pop_last();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (linked_node->is_group_output_node()) {
|
else if (linked_node->is_group_output()) {
|
||||||
if (linked_node.node_ref() != context_->tree().group_output_node()) {
|
if (linked_node.bnode() != context_->btree().group_output_node()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (context_->is_root()) {
|
if (context_->is_root()) {
|
||||||
@@ -276,7 +276,7 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
|
|||||||
path_info.sockets.pop_last();
|
path_info.sockets.pop_last();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (linked_node->is_group_node()) {
|
else if (linked_node->is_group()) {
|
||||||
/* Follow the links within the nested node group. */
|
/* Follow the links within the nested node group. */
|
||||||
path_info.sockets.append(linked_socket);
|
path_info.sockets.append(linked_socket);
|
||||||
const Vector<DOutputSocket> sockets_in_group =
|
const Vector<DOutputSocket> sockets_in_group =
|
||||||
@@ -310,7 +310,8 @@ static dot::Cluster *get_dot_cluster_for_context(
|
|||||||
}
|
}
|
||||||
dot::Cluster *parent_cluster = get_dot_cluster_for_context(
|
dot::Cluster *parent_cluster = get_dot_cluster_for_context(
|
||||||
digraph, parent_context, dot_clusters);
|
digraph, parent_context, dot_clusters);
|
||||||
std::string cluster_name = context->tree().name() + " / " + context->parent_node()->name();
|
std::string cluster_name = StringRef(context->btree().id.name + 2) + " / " +
|
||||||
|
context->parent_node()->name;
|
||||||
dot::Cluster &cluster = digraph.new_cluster(cluster_name);
|
dot::Cluster &cluster = digraph.new_cluster(cluster_name);
|
||||||
cluster.set_parent_cluster(parent_cluster);
|
cluster.set_parent_cluster(parent_cluster);
|
||||||
return &cluster;
|
return &cluster;
|
||||||
@@ -328,11 +329,11 @@ std::string DerivedNodeTree::to_dot() const
|
|||||||
|
|
||||||
this->foreach_node([&](DNode node) {
|
this->foreach_node([&](DNode node) {
|
||||||
/* Ignore nodes that should not show up in the final output. */
|
/* Ignore nodes that should not show up in the final output. */
|
||||||
if (node->is_muted() || node->is_group_node() || node->is_reroute_node() || node->is_frame()) {
|
if (node->is_muted() || node->is_group() || node->is_reroute() || node->is_frame()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!node.context()->is_root()) {
|
if (!node.context()->is_root()) {
|
||||||
if (node->is_group_input_node() || node->is_group_output_node()) {
|
if (node->is_group_input() || node->is_group_output()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,22 +346,22 @@ std::string DerivedNodeTree::to_dot() const
|
|||||||
|
|
||||||
Vector<std::string> input_names;
|
Vector<std::string> input_names;
|
||||||
Vector<std::string> output_names;
|
Vector<std::string> output_names;
|
||||||
for (const InputSocketRef *socket : node->inputs()) {
|
for (const bNodeSocket *socket : node->input_sockets()) {
|
||||||
if (socket->is_available()) {
|
if (socket->is_available()) {
|
||||||
input_names.append(socket->name());
|
input_names.append(socket->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const OutputSocketRef *socket : node->outputs()) {
|
for (const bNodeSocket *socket : node->output_sockets()) {
|
||||||
if (socket->is_available()) {
|
if (socket->is_available()) {
|
||||||
output_names.append(socket->name());
|
output_names.append(socket->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dot::NodeWithSocketsRef dot_node_with_sockets = dot::NodeWithSocketsRef(
|
dot::NodeWithSocketsRef dot_node_with_sockets = dot::NodeWithSocketsRef(
|
||||||
dot_node, node->name(), input_names, output_names);
|
dot_node, node->name, input_names, output_names);
|
||||||
|
|
||||||
int input_index = 0;
|
int input_index = 0;
|
||||||
for (const InputSocketRef *socket : node->inputs()) {
|
for (const bNodeSocket *socket : node->input_sockets()) {
|
||||||
if (socket->is_available()) {
|
if (socket->is_available()) {
|
||||||
dot_input_sockets.add_new(DInputSocket{node.context(), socket},
|
dot_input_sockets.add_new(DInputSocket{node.context(), socket},
|
||||||
dot_node_with_sockets.input(input_index));
|
dot_node_with_sockets.input(input_index));
|
||||||
@@ -368,7 +369,7 @@ std::string DerivedNodeTree::to_dot() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
int output_index = 0;
|
int output_index = 0;
|
||||||
for (const OutputSocketRef *socket : node->outputs()) {
|
for (const bNodeSocket *socket : node->output_sockets()) {
|
||||||
if (socket->is_available()) {
|
if (socket->is_available()) {
|
||||||
dot_output_sockets.add_new(DOutputSocket{node.context(), socket},
|
dot_output_sockets.add_new(DOutputSocket{node.context(), socket},
|
||||||
dot_node_with_sockets.output(output_index));
|
dot_node_with_sockets.output(output_index));
|
||||||
@@ -392,7 +393,7 @@ std::string DerivedNodeTree::to_dot() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dot::Node &dot_node = *dot_floating_inputs.lookup_or_add_cb(from_socket, [&]() {
|
dot::Node &dot_node = *dot_floating_inputs.lookup_or_add_cb(from_socket, [&]() {
|
||||||
dot::Node &dot_node = digraph.new_node(from_socket->name());
|
dot::Node &dot_node = digraph.new_node(from_socket->name);
|
||||||
dot_node.set_background_color("white");
|
dot_node.set_background_color("white");
|
||||||
dot_node.set_shape(dot::Attr_shape::Ellipse);
|
dot_node.set_shape(dot::Attr_shape::Ellipse);
|
||||||
dot_node.set_parent_cluster(
|
dot_node.set_parent_cluster(
|
||||||
|
|||||||
@@ -89,17 +89,17 @@ TreeLog &ModifierLog::lookup_or_add_tree_log(LogByTreeContext &log_by_tree_conte
|
|||||||
destruct_ptr<TreeLog> owned_tree_log = allocator_.construct<TreeLog>();
|
destruct_ptr<TreeLog> owned_tree_log = allocator_.construct<TreeLog>();
|
||||||
tree_log = owned_tree_log.get();
|
tree_log = owned_tree_log.get();
|
||||||
log_by_tree_context.add_new(&tree_context, tree_log);
|
log_by_tree_context.add_new(&tree_context, tree_log);
|
||||||
parent_log.child_logs_.add_new(tree_context.parent_node()->name(), std::move(owned_tree_log));
|
parent_log.child_logs_.add_new(tree_context.parent_node()->name, std::move(owned_tree_log));
|
||||||
return *tree_log;
|
return *tree_log;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeLog &ModifierLog::lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node)
|
NodeLog &ModifierLog::lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node)
|
||||||
{
|
{
|
||||||
TreeLog &tree_log = this->lookup_or_add_tree_log(log_by_tree_context, *node.context());
|
TreeLog &tree_log = this->lookup_or_add_tree_log(log_by_tree_context, *node.context());
|
||||||
NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name(), [&]() {
|
NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name, [&]() {
|
||||||
destruct_ptr<NodeLog> node_log = allocator_.construct<NodeLog>();
|
destruct_ptr<NodeLog> node_log = allocator_.construct<NodeLog>();
|
||||||
node_log->input_logs_.resize(node->inputs().size());
|
node_log->input_logs_.resize(node->input_sockets().size());
|
||||||
node_log->output_logs_.resize(node->outputs().size());
|
node_log->output_logs_.resize(node->output_sockets().size());
|
||||||
return node_log;
|
return node_log;
|
||||||
});
|
});
|
||||||
return node_log;
|
return node_log;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ void GeoNodeExecParams::check_input_geometry_set(StringRef identifier,
|
|||||||
const GeometrySet &geometry_set) const
|
const GeometrySet &geometry_set) const
|
||||||
{
|
{
|
||||||
const SocketDeclaration &decl =
|
const SocketDeclaration &decl =
|
||||||
*provider_->dnode->input_by_identifier(identifier).bsocket()->runtime->declaration;
|
*provider_->dnode->input_by_identifier(identifier).runtime->declaration;
|
||||||
const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl);
|
const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl);
|
||||||
if (geo_decl == nullptr) {
|
if (geo_decl == nullptr) {
|
||||||
return;
|
return;
|
||||||
@@ -118,9 +118,9 @@ void GeoNodeExecParams::check_output_geometry_set(const GeometrySet &geometry_se
|
|||||||
|
|
||||||
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
|
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
|
||||||
{
|
{
|
||||||
for (const InputSocketRef *socket : provider_->dnode->inputs()) {
|
for (const bNodeSocket *socket : provider_->dnode->runtime->inputs) {
|
||||||
if (socket->is_available() && socket->name() == name) {
|
if (socket->is_available() && socket->name == name) {
|
||||||
return socket->bsocket();
|
return socket;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,10 +140,10 @@ void GeoNodeExecParams::set_default_remaining_outputs()
|
|||||||
void GeoNodeExecParams::check_input_access(StringRef identifier,
|
void GeoNodeExecParams::check_input_access(StringRef identifier,
|
||||||
const CPPType *requested_type) const
|
const CPPType *requested_type) const
|
||||||
{
|
{
|
||||||
bNodeSocket *found_socket = nullptr;
|
const bNodeSocket *found_socket = nullptr;
|
||||||
for (const InputSocketRef *socket : provider_->dnode->inputs()) {
|
for (const bNodeSocket *socket : provider_->dnode->input_sockets()) {
|
||||||
if (socket->identifier() == identifier) {
|
if (socket->identifier == identifier) {
|
||||||
found_socket = socket->bsocket();
|
found_socket = socket;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,9 +151,9 @@ void GeoNodeExecParams::check_input_access(StringRef identifier,
|
|||||||
if (found_socket == nullptr) {
|
if (found_socket == nullptr) {
|
||||||
std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n";
|
std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n";
|
||||||
std::cout << "Possible identifiers are: ";
|
std::cout << "Possible identifiers are: ";
|
||||||
for (const InputSocketRef *socket : provider_->dnode->inputs()) {
|
for (const bNodeSocket *socket : provider_->dnode->input_sockets()) {
|
||||||
if (socket->is_available()) {
|
if (socket->is_available()) {
|
||||||
std::cout << "'" << socket->identifier() << "', ";
|
std::cout << "'" << socket->identifier << "', ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
@@ -182,10 +182,10 @@ void GeoNodeExecParams::check_input_access(StringRef identifier,
|
|||||||
|
|
||||||
void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType &value_type) const
|
void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType &value_type) const
|
||||||
{
|
{
|
||||||
bNodeSocket *found_socket = nullptr;
|
const bNodeSocket *found_socket = nullptr;
|
||||||
for (const OutputSocketRef *socket : provider_->dnode->outputs()) {
|
for (const bNodeSocket *socket : provider_->dnode->output_sockets()) {
|
||||||
if (socket->identifier() == identifier) {
|
if (socket->identifier == identifier) {
|
||||||
found_socket = socket->bsocket();
|
found_socket = socket;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,9 +193,9 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType
|
|||||||
if (found_socket == nullptr) {
|
if (found_socket == nullptr) {
|
||||||
std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n";
|
std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n";
|
||||||
std::cout << "Possible identifiers are: ";
|
std::cout << "Possible identifiers are: ";
|
||||||
for (const OutputSocketRef *socket : provider_->dnode->outputs()) {
|
for (const bNodeSocket *socket : provider_->dnode->output_sockets()) {
|
||||||
if (socket->is_available()) {
|
if (!(socket->flag & SOCK_UNAVAIL)) {
|
||||||
std::cout << "'" << socket->identifier() << "', ";
|
std::cout << "'" << socket->identifier << "', ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
#include "NOD_multi_function.hh"
|
#include "NOD_multi_function.hh"
|
||||||
|
|
||||||
|
#include "BKE_node.h"
|
||||||
|
|
||||||
namespace blender::nodes {
|
namespace blender::nodes {
|
||||||
|
|
||||||
NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree)
|
NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree)
|
||||||
{
|
{
|
||||||
for (const NodeTreeRef *tree_ref : tree.used_node_tree_refs()) {
|
for (const bNodeTree *btree : tree.used_btrees()) {
|
||||||
bNodeTree *btree = tree_ref->btree();
|
for (const bNode *bnode : btree->all_nodes()) {
|
||||||
for (const NodeRef *node : tree_ref->nodes()) {
|
|
||||||
bNode *bnode = node->bnode();
|
|
||||||
if (bnode->typeinfo->build_multi_function == nullptr) {
|
if (bnode->typeinfo->build_multi_function == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,679 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include "NOD_node_tree_ref.hh"
|
|
||||||
|
|
||||||
#include "BLI_dot_export.hh"
|
|
||||||
#include "BLI_stack.hh"
|
|
||||||
|
|
||||||
#include "RNA_prototypes.h"
|
|
||||||
|
|
||||||
namespace blender::nodes {
|
|
||||||
|
|
||||||
NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
|
|
||||||
{
|
|
||||||
Map<bNode *, NodeRef *> node_mapping;
|
|
||||||
|
|
||||||
LISTBASE_FOREACH (bNode *, bnode, &btree->nodes) {
|
|
||||||
NodeRef &node = *allocator_.construct<NodeRef>().release();
|
|
||||||
|
|
||||||
node.tree_ = this;
|
|
||||||
node.bnode_ = bnode;
|
|
||||||
node.id_ = nodes_by_id_.append_and_get_index(&node);
|
|
||||||
|
|
||||||
LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->inputs) {
|
|
||||||
InputSocketRef &socket = *allocator_.construct<InputSocketRef>().release();
|
|
||||||
socket.node_ = &node;
|
|
||||||
socket.index_ = node.inputs_.append_and_get_index(&socket);
|
|
||||||
socket.is_input_ = true;
|
|
||||||
socket.bsocket_ = bsocket;
|
|
||||||
socket.id_ = sockets_by_id_.append_and_get_index(&socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->outputs) {
|
|
||||||
OutputSocketRef &socket = *allocator_.construct<OutputSocketRef>().release();
|
|
||||||
socket.node_ = &node;
|
|
||||||
socket.index_ = node.outputs_.append_and_get_index(&socket);
|
|
||||||
socket.is_input_ = false;
|
|
||||||
socket.bsocket_ = bsocket;
|
|
||||||
socket.id_ = sockets_by_id_.append_and_get_index(&socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
LISTBASE_FOREACH (bNodeLink *, blink, &bnode->internal_links) {
|
|
||||||
InternalLinkRef &internal_link = *allocator_.construct<InternalLinkRef>().release();
|
|
||||||
internal_link.blink_ = blink;
|
|
||||||
for (InputSocketRef *socket_ref : node.inputs_) {
|
|
||||||
if (socket_ref->bsocket_ == blink->fromsock) {
|
|
||||||
internal_link.from_ = socket_ref;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (OutputSocketRef *socket_ref : node.outputs_) {
|
|
||||||
if (socket_ref->bsocket_ == blink->tosock) {
|
|
||||||
internal_link.to_ = socket_ref;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BLI_assert(internal_link.from_ != nullptr);
|
|
||||||
BLI_assert(internal_link.to_ != nullptr);
|
|
||||||
node.internal_links_.append(&internal_link);
|
|
||||||
}
|
|
||||||
|
|
||||||
input_sockets_.extend(node.inputs_.as_span());
|
|
||||||
output_sockets_.extend(node.outputs_.as_span());
|
|
||||||
|
|
||||||
node_mapping.add_new(bnode, &node);
|
|
||||||
}
|
|
||||||
|
|
||||||
LISTBASE_FOREACH (bNodeLink *, blink, &btree->links) {
|
|
||||||
OutputSocketRef &from_socket = this->find_output_socket(
|
|
||||||
node_mapping, blink->fromnode, blink->fromsock);
|
|
||||||
InputSocketRef &to_socket = this->find_input_socket(
|
|
||||||
node_mapping, blink->tonode, blink->tosock);
|
|
||||||
|
|
||||||
LinkRef &link = *allocator_.construct<LinkRef>().release();
|
|
||||||
link.from_ = &from_socket;
|
|
||||||
link.to_ = &to_socket;
|
|
||||||
link.blink_ = blink;
|
|
||||||
|
|
||||||
links_.append(&link);
|
|
||||||
|
|
||||||
from_socket.directly_linked_links_.append(&link);
|
|
||||||
to_socket.directly_linked_links_.append(&link);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (InputSocketRef *input_socket : input_sockets_) {
|
|
||||||
if (input_socket->is_multi_input_socket()) {
|
|
||||||
std::sort(input_socket->directly_linked_links_.begin(),
|
|
||||||
input_socket->directly_linked_links_.end(),
|
|
||||||
[&](const LinkRef *a, const LinkRef *b) -> bool {
|
|
||||||
int index_a = a->blink()->multi_input_socket_index;
|
|
||||||
int index_b = b->blink()->multi_input_socket_index;
|
|
||||||
return index_a > index_b;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->create_socket_identifier_maps();
|
|
||||||
this->create_linked_socket_caches();
|
|
||||||
|
|
||||||
for (NodeRef *node : nodes_by_id_) {
|
|
||||||
const bNodeType *nodetype = node->bnode_->typeinfo;
|
|
||||||
nodes_by_type_.add(nodetype, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Span<const NodeRef *> group_output_nodes = this->nodes_by_type("NodeGroupOutput");
|
|
||||||
if (group_output_nodes.is_empty()) {
|
|
||||||
group_output_node_ = nullptr;
|
|
||||||
}
|
|
||||||
else if (group_output_nodes.size() == 1) {
|
|
||||||
group_output_node_ = group_output_nodes.first();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (const NodeRef *group_output : group_output_nodes) {
|
|
||||||
if (group_output->bnode_->flag & NODE_DO_OUTPUT) {
|
|
||||||
group_output_node_ = group_output;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeTreeRef::~NodeTreeRef()
|
|
||||||
{
|
|
||||||
/* The destructor has to be called manually, because these types are allocated in a linear
|
|
||||||
* allocator. */
|
|
||||||
for (NodeRef *node : nodes_by_id_) {
|
|
||||||
node->~NodeRef();
|
|
||||||
}
|
|
||||||
for (InputSocketRef *socket : input_sockets_) {
|
|
||||||
socket->~InputSocketRef();
|
|
||||||
}
|
|
||||||
for (OutputSocketRef *socket : output_sockets_) {
|
|
||||||
socket->~OutputSocketRef();
|
|
||||||
}
|
|
||||||
for (LinkRef *link : links_) {
|
|
||||||
link->~LinkRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InputSocketRef &NodeTreeRef::find_input_socket(Map<bNode *, NodeRef *> &node_mapping,
|
|
||||||
bNode *bnode,
|
|
||||||
bNodeSocket *bsocket)
|
|
||||||
{
|
|
||||||
NodeRef *node = node_mapping.lookup(bnode);
|
|
||||||
for (InputSocketRef *socket : node->inputs_) {
|
|
||||||
if (socket->bsocket_ == bsocket) {
|
|
||||||
return *socket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
return *node->inputs_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputSocketRef &NodeTreeRef::find_output_socket(Map<bNode *, NodeRef *> &node_mapping,
|
|
||||||
bNode *bnode,
|
|
||||||
bNodeSocket *bsocket)
|
|
||||||
{
|
|
||||||
NodeRef *node = node_mapping.lookup(bnode);
|
|
||||||
for (OutputSocketRef *socket : node->outputs_) {
|
|
||||||
if (socket->bsocket_ == bsocket) {
|
|
||||||
return *socket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
return *node->outputs_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeTreeRef::create_linked_socket_caches()
|
|
||||||
{
|
|
||||||
for (InputSocketRef *socket : input_sockets_) {
|
|
||||||
/* Find directly linked socket based on incident links. */
|
|
||||||
Vector<const SocketRef *> directly_linked_sockets;
|
|
||||||
for (LinkRef *link : socket->directly_linked_links_) {
|
|
||||||
directly_linked_sockets.append(link->from_);
|
|
||||||
}
|
|
||||||
socket->directly_linked_sockets_ = allocator_.construct_array_copy(
|
|
||||||
directly_linked_sockets.as_span());
|
|
||||||
|
|
||||||
/* Find logically linked sockets. */
|
|
||||||
Vector<const SocketRef *> logically_linked_sockets;
|
|
||||||
Vector<const SocketRef *> logically_linked_skipped_sockets;
|
|
||||||
Vector<const InputSocketRef *> seen_sockets_stack;
|
|
||||||
socket->foreach_logical_origin(
|
|
||||||
[&](const OutputSocketRef &origin) { logically_linked_sockets.append(&origin); },
|
|
||||||
[&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); },
|
|
||||||
false,
|
|
||||||
seen_sockets_stack);
|
|
||||||
if (logically_linked_sockets == directly_linked_sockets) {
|
|
||||||
socket->logically_linked_sockets_ = socket->directly_linked_sockets_;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
socket->logically_linked_sockets_ = allocator_.construct_array_copy(
|
|
||||||
logically_linked_sockets.as_span());
|
|
||||||
}
|
|
||||||
socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy(
|
|
||||||
logically_linked_skipped_sockets.as_span());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (OutputSocketRef *socket : output_sockets_) {
|
|
||||||
/* Find directly linked socket based on incident links. */
|
|
||||||
Vector<const SocketRef *> directly_linked_sockets;
|
|
||||||
for (LinkRef *link : socket->directly_linked_links_) {
|
|
||||||
directly_linked_sockets.append(link->to_);
|
|
||||||
}
|
|
||||||
socket->directly_linked_sockets_ = allocator_.construct_array_copy(
|
|
||||||
directly_linked_sockets.as_span());
|
|
||||||
|
|
||||||
/* Find logically linked sockets. */
|
|
||||||
Vector<const SocketRef *> logically_linked_sockets;
|
|
||||||
Vector<const SocketRef *> logically_linked_skipped_sockets;
|
|
||||||
Vector<const OutputSocketRef *> handled_sockets;
|
|
||||||
socket->foreach_logical_target(
|
|
||||||
[&](const InputSocketRef &target) { logically_linked_sockets.append(&target); },
|
|
||||||
[&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); },
|
|
||||||
handled_sockets);
|
|
||||||
if (logically_linked_sockets == directly_linked_sockets) {
|
|
||||||
socket->logically_linked_sockets_ = socket->directly_linked_sockets_;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
socket->logically_linked_sockets_ = allocator_.construct_array_copy(
|
|
||||||
logically_linked_sockets.as_span());
|
|
||||||
}
|
|
||||||
socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy(
|
|
||||||
logically_linked_skipped_sockets.as_span());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputSocketRef::foreach_logical_origin(
|
|
||||||
FunctionRef<void(const OutputSocketRef &)> origin_fn,
|
|
||||||
FunctionRef<void(const SocketRef &)> skipped_fn,
|
|
||||||
bool only_follow_first_input_link,
|
|
||||||
Vector<const InputSocketRef *> &seen_sockets_stack) const
|
|
||||||
{
|
|
||||||
/* Protect against loops. */
|
|
||||||
if (seen_sockets_stack.contains(this)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seen_sockets_stack.append(this);
|
|
||||||
|
|
||||||
Span<const LinkRef *> links_to_check = this->directly_linked_links();
|
|
||||||
if (only_follow_first_input_link) {
|
|
||||||
links_to_check = links_to_check.take_front(1);
|
|
||||||
}
|
|
||||||
for (const LinkRef *link : links_to_check) {
|
|
||||||
if (link->is_muted()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const OutputSocketRef &origin = link->from();
|
|
||||||
const NodeRef &origin_node = origin.node();
|
|
||||||
if (!origin.is_available()) {
|
|
||||||
/* Non available sockets are ignored. */
|
|
||||||
}
|
|
||||||
else if (origin_node.is_reroute_node()) {
|
|
||||||
const InputSocketRef &reroute_input = origin_node.input(0);
|
|
||||||
const OutputSocketRef &reroute_output = origin_node.output(0);
|
|
||||||
skipped_fn.call_safe(reroute_input);
|
|
||||||
skipped_fn.call_safe(reroute_output);
|
|
||||||
reroute_input.foreach_logical_origin(origin_fn, skipped_fn, false, seen_sockets_stack);
|
|
||||||
}
|
|
||||||
else if (origin_node.is_muted()) {
|
|
||||||
for (const InternalLinkRef *internal_link : origin_node.internal_links()) {
|
|
||||||
if (&internal_link->to() == &origin) {
|
|
||||||
const InputSocketRef &mute_input = internal_link->from();
|
|
||||||
skipped_fn.call_safe(origin);
|
|
||||||
skipped_fn.call_safe(mute_input);
|
|
||||||
mute_input.foreach_logical_origin(origin_fn, skipped_fn, true, seen_sockets_stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
origin_fn(origin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
seen_sockets_stack.pop_last();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OutputSocketRef::foreach_logical_target(
|
|
||||||
FunctionRef<void(const InputSocketRef &)> target_fn,
|
|
||||||
FunctionRef<void(const SocketRef &)> skipped_fn,
|
|
||||||
Vector<const OutputSocketRef *> &seen_sockets_stack) const
|
|
||||||
{
|
|
||||||
/* Protect against loops. */
|
|
||||||
if (seen_sockets_stack.contains(this)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seen_sockets_stack.append(this);
|
|
||||||
|
|
||||||
for (const LinkRef *link : this->directly_linked_links()) {
|
|
||||||
if (link->is_muted()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const InputSocketRef &target = link->to();
|
|
||||||
const NodeRef &target_node = target.node();
|
|
||||||
if (!target.is_available()) {
|
|
||||||
/* Non available sockets are ignored. */
|
|
||||||
}
|
|
||||||
else if (target_node.is_reroute_node()) {
|
|
||||||
const OutputSocketRef &reroute_output = target_node.output(0);
|
|
||||||
skipped_fn.call_safe(target);
|
|
||||||
skipped_fn.call_safe(reroute_output);
|
|
||||||
reroute_output.foreach_logical_target(target_fn, skipped_fn, seen_sockets_stack);
|
|
||||||
}
|
|
||||||
else if (target_node.is_muted()) {
|
|
||||||
skipped_fn.call_safe(target);
|
|
||||||
for (const InternalLinkRef *internal_link : target_node.internal_links()) {
|
|
||||||
if (&internal_link->from() == &target) {
|
|
||||||
/* The internal link only forwards the first incoming link. */
|
|
||||||
if (target.is_multi_input_socket()) {
|
|
||||||
if (target.directly_linked_links()[0] != link) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const OutputSocketRef &mute_output = internal_link->to();
|
|
||||||
skipped_fn.call_safe(target);
|
|
||||||
skipped_fn.call_safe(mute_output);
|
|
||||||
mute_output.foreach_logical_target(target_fn, skipped_fn, seen_sockets_stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
target_fn(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
seen_sockets_stack.pop_last();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct SocketByIdentifierMap {
|
|
||||||
SocketIndexByIdentifierMap *map = nullptr;
|
|
||||||
std::unique_ptr<SocketIndexByIdentifierMap> owned_map;
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
static std::unique_ptr<SocketIndexByIdentifierMap> create_identifier_map(const ListBase &sockets)
|
|
||||||
{
|
|
||||||
std::unique_ptr<SocketIndexByIdentifierMap> map = std::make_unique<SocketIndexByIdentifierMap>();
|
|
||||||
int index;
|
|
||||||
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sockets, index) {
|
|
||||||
map->add_new(socket->identifier, index);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is not threadsafe. */
|
|
||||||
static SocketByIdentifierMap get_or_create_identifier_map(
|
|
||||||
const bNode &node, const ListBase &sockets, const bNodeSocketTemplate *sockets_template)
|
|
||||||
{
|
|
||||||
SocketByIdentifierMap map;
|
|
||||||
if (sockets_template == nullptr) {
|
|
||||||
if (BLI_listbase_is_empty(&sockets)) {
|
|
||||||
static SocketIndexByIdentifierMap empty_map;
|
|
||||||
map.map = &empty_map;
|
|
||||||
}
|
|
||||||
else if (node.type == NODE_REROUTE) {
|
|
||||||
if (&node.inputs == &sockets) {
|
|
||||||
static SocketIndexByIdentifierMap reroute_input_map = [] {
|
|
||||||
SocketIndexByIdentifierMap map;
|
|
||||||
map.add_new("Input", 0);
|
|
||||||
return map;
|
|
||||||
}();
|
|
||||||
map.map = &reroute_input_map;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
static SocketIndexByIdentifierMap reroute_output_map = [] {
|
|
||||||
SocketIndexByIdentifierMap map;
|
|
||||||
map.add_new("Output", 0);
|
|
||||||
return map;
|
|
||||||
}();
|
|
||||||
map.map = &reroute_output_map;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* The node has a dynamic amount of sockets. Therefore we need to create a new map. */
|
|
||||||
map.owned_map = create_identifier_map(sockets);
|
|
||||||
map.map = &*map.owned_map;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Cache only one map for nodes that have the same sockets. */
|
|
||||||
static Map<const bNodeSocketTemplate *, std::unique_ptr<SocketIndexByIdentifierMap>> maps;
|
|
||||||
map.map = &*maps.lookup_or_add_cb(sockets_template,
|
|
||||||
[&]() { return create_identifier_map(sockets); });
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeTreeRef::create_socket_identifier_maps()
|
|
||||||
{
|
|
||||||
/* `get_or_create_identifier_map` is not threadsafe, therefore we have to hold a lock here. */
|
|
||||||
static std::mutex mutex;
|
|
||||||
std::lock_guard lock{mutex};
|
|
||||||
|
|
||||||
for (NodeRef *node : nodes_by_id_) {
|
|
||||||
bNode &bnode = *node->bnode_;
|
|
||||||
SocketByIdentifierMap inputs_map = get_or_create_identifier_map(
|
|
||||||
bnode, bnode.inputs, bnode.typeinfo->inputs);
|
|
||||||
SocketByIdentifierMap outputs_map = get_or_create_identifier_map(
|
|
||||||
bnode, bnode.outputs, bnode.typeinfo->outputs);
|
|
||||||
node->input_index_by_identifier_ = inputs_map.map;
|
|
||||||
node->output_index_by_identifier_ = outputs_map.map;
|
|
||||||
if (inputs_map.owned_map) {
|
|
||||||
owned_identifier_maps_.append(std::move(inputs_map.owned_map));
|
|
||||||
}
|
|
||||||
if (outputs_map.owned_map) {
|
|
||||||
owned_identifier_maps_.append(std::move(outputs_map.owned_map));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool has_link_cycles_recursive(const NodeRef &node,
|
|
||||||
MutableSpan<bool> visited,
|
|
||||||
MutableSpan<bool> is_in_stack)
|
|
||||||
{
|
|
||||||
const int node_id = node.id();
|
|
||||||
if (is_in_stack[node_id]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (visited[node_id]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
visited[node_id] = true;
|
|
||||||
is_in_stack[node_id] = true;
|
|
||||||
|
|
||||||
for (const OutputSocketRef *from_socket : node.outputs()) {
|
|
||||||
if (!from_socket->is_available()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) {
|
|
||||||
if (!to_socket->is_available()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const NodeRef &to_node = to_socket->node();
|
|
||||||
if (has_link_cycles_recursive(to_node, visited, is_in_stack)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is_in_stack[node_id] = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NodeTreeRef::has_link_cycles() const
|
|
||||||
{
|
|
||||||
const int node_amount = nodes_by_id_.size();
|
|
||||||
Array<bool> visited(node_amount, false);
|
|
||||||
Array<bool> is_in_stack(node_amount, false);
|
|
||||||
|
|
||||||
for (const NodeRef *node : nodes_by_id_) {
|
|
||||||
if (has_link_cycles_recursive(*node, visited, is_in_stack)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NodeTreeRef::has_undefined_nodes_or_sockets() const
|
|
||||||
{
|
|
||||||
for (const NodeRef *node : nodes_by_id_) {
|
|
||||||
if (node->is_undefined()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const SocketRef *socket : sockets_by_id_) {
|
|
||||||
if (socket->is_undefined()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NodeRef::any_input_is_directly_linked() const
|
|
||||||
{
|
|
||||||
for (const SocketRef *socket : inputs_) {
|
|
||||||
if (!socket->directly_linked_sockets().is_empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NodeRef::any_output_is_directly_linked() const
|
|
||||||
{
|
|
||||||
for (const SocketRef *socket : outputs_) {
|
|
||||||
if (!socket->directly_linked_sockets().is_empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NodeRef::any_socket_is_directly_linked(eNodeSocketInOut in_out) const
|
|
||||||
{
|
|
||||||
if (in_out == SOCK_IN) {
|
|
||||||
return this->any_input_is_directly_linked();
|
|
||||||
}
|
|
||||||
return this->any_output_is_directly_linked();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ToposortNodeState {
|
|
||||||
bool is_done = false;
|
|
||||||
bool is_in_stack = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direction,
|
|
||||||
const NodeRef &start_node,
|
|
||||||
MutableSpan<ToposortNodeState> node_states,
|
|
||||||
NodeTreeRef::ToposortResult &result)
|
|
||||||
{
|
|
||||||
struct Item {
|
|
||||||
const NodeRef *node;
|
|
||||||
/* Index of the next socket that is checked in the depth-first search. */
|
|
||||||
int socket_index = 0;
|
|
||||||
/* Link index in the next socket that is checked in the depth-first search. */
|
|
||||||
int link_index = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Do a depth-first search to sort nodes topologically. */
|
|
||||||
Stack<Item, 64> nodes_to_check;
|
|
||||||
nodes_to_check.push({&start_node});
|
|
||||||
node_states[start_node.id()].is_in_stack = true;
|
|
||||||
while (!nodes_to_check.is_empty()) {
|
|
||||||
Item &item = nodes_to_check.peek();
|
|
||||||
const NodeRef &node = *item.node;
|
|
||||||
const Span<const SocketRef *> sockets = node.sockets(
|
|
||||||
direction == NodeTreeRef::ToposortDirection::LeftToRight ? SOCK_IN : SOCK_OUT);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (item.socket_index == sockets.size()) {
|
|
||||||
/* All sockets have already been visited. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const SocketRef &socket = *sockets[item.socket_index];
|
|
||||||
const Span<const SocketRef *> linked_sockets = socket.directly_linked_sockets();
|
|
||||||
if (item.link_index == linked_sockets.size()) {
|
|
||||||
/* All links connected to this socket have already been visited. */
|
|
||||||
item.socket_index++;
|
|
||||||
item.link_index = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const SocketRef &linked_socket = *linked_sockets[item.link_index];
|
|
||||||
const NodeRef &linked_node = linked_socket.node();
|
|
||||||
ToposortNodeState &linked_node_state = node_states[linked_node.id()];
|
|
||||||
if (linked_node_state.is_done) {
|
|
||||||
/* The linked node has already been visited. */
|
|
||||||
item.link_index++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (linked_node_state.is_in_stack) {
|
|
||||||
result.has_cycle = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nodes_to_check.push({&linked_node});
|
|
||||||
linked_node_state.is_in_stack = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If no other element has been pushed, the current node can be pushed to the sorted list. */
|
|
||||||
if (&item == &nodes_to_check.peek()) {
|
|
||||||
ToposortNodeState &node_state = node_states[node.id()];
|
|
||||||
node_state.is_done = true;
|
|
||||||
node_state.is_in_stack = false;
|
|
||||||
result.sorted_nodes.append(&node);
|
|
||||||
nodes_to_check.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const
|
|
||||||
{
|
|
||||||
ToposortResult result;
|
|
||||||
result.sorted_nodes.reserve(nodes_by_id_.size());
|
|
||||||
|
|
||||||
Array<ToposortNodeState> node_states(nodes_by_id_.size());
|
|
||||||
|
|
||||||
for (const NodeRef *node : nodes_by_id_) {
|
|
||||||
if (node_states[node->id()].is_done) {
|
|
||||||
/* Ignore nodes that are done already. */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (node->any_socket_is_directly_linked(
|
|
||||||
direction == ToposortDirection::LeftToRight ? SOCK_OUT : SOCK_IN)) {
|
|
||||||
/* Ignore non-start nodes. */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
toposort_from_start_node(direction, *node, node_states, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the loop above forgot some nodes because there is a cycle. */
|
|
||||||
if (result.sorted_nodes.size() < nodes_by_id_.size()) {
|
|
||||||
result.has_cycle = true;
|
|
||||||
for (const NodeRef *node : nodes_by_id_) {
|
|
||||||
if (node_states[node->id()].is_done) {
|
|
||||||
/* Ignore nodes that are done already. */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Start toposort at this node which is somewhere in the middle of a loop. */
|
|
||||||
toposort_from_start_node(direction, *node, node_states, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BLI_assert(result.sorted_nodes.size() == nodes_by_id_.size());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NodeRef *NodeTreeRef::find_node(const bNode &bnode) const
|
|
||||||
{
|
|
||||||
for (const NodeRef *node : this->nodes_by_type(bnode.typeinfo)) {
|
|
||||||
if (node->bnode_ == &bnode) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string NodeTreeRef::to_dot() const
|
|
||||||
{
|
|
||||||
dot::DirectedGraph digraph;
|
|
||||||
digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
|
|
||||||
|
|
||||||
Map<const NodeRef *, dot::NodeWithSocketsRef> dot_nodes;
|
|
||||||
|
|
||||||
for (const NodeRef *node : nodes_by_id_) {
|
|
||||||
dot::Node &dot_node = digraph.new_node("");
|
|
||||||
dot_node.set_background_color("white");
|
|
||||||
|
|
||||||
Vector<std::string> input_names;
|
|
||||||
Vector<std::string> output_names;
|
|
||||||
for (const InputSocketRef *socket : node->inputs()) {
|
|
||||||
input_names.append(socket->name());
|
|
||||||
}
|
|
||||||
for (const OutputSocketRef *socket : node->outputs()) {
|
|
||||||
output_names.append(socket->name());
|
|
||||||
}
|
|
||||||
|
|
||||||
dot_nodes.add_new(node,
|
|
||||||
dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const OutputSocketRef *from_socket : output_sockets_) {
|
|
||||||
for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) {
|
|
||||||
dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(&from_socket->node());
|
|
||||||
dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(&to_socket->node());
|
|
||||||
|
|
||||||
digraph.new_edge(from_dot_node.output(from_socket->index()),
|
|
||||||
to_dot_node.input(to_socket->index()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return digraph.to_dot_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree)
|
|
||||||
{
|
|
||||||
return *node_tree_refs.lookup_or_add_cb(&btree,
|
|
||||||
[&]() { return std::make_unique<NodeTreeRef>(&btree); });
|
|
||||||
}
|
|
||||||
|
|
||||||
PointerRNA NodeRef::rna() const
|
|
||||||
{
|
|
||||||
PointerRNA rna;
|
|
||||||
RNA_pointer_create(&tree_->btree()->id, &RNA_Node, bnode_, &rna);
|
|
||||||
return rna;
|
|
||||||
}
|
|
||||||
|
|
||||||
PointerRNA SocketRef::rna() const
|
|
||||||
{
|
|
||||||
PointerRNA rna;
|
|
||||||
RNA_pointer_create(&this->tree().btree()->id, &RNA_NodeSocket, bsocket_, &rna);
|
|
||||||
return rna;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace blender::nodes
|
|
||||||
@@ -59,6 +59,8 @@
|
|||||||
#include "RE_pipeline.h"
|
#include "RE_pipeline.h"
|
||||||
#include "RE_texture.h"
|
#include "RE_texture.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
|
||||||
bool sh_node_poll_default(struct bNodeType *ntype,
|
bool sh_node_poll_default(struct bNodeType *ntype,
|
||||||
struct bNodeTree *ntree,
|
struct bNodeTree *ntree,
|
||||||
const char **r_disabled_hint);
|
const char **r_disabled_hint);
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ class ColorBandFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilder &builder)
|
static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &bnode = builder.node();
|
const bNode &bnode = builder.node();
|
||||||
const ColorBand *color_band = (const ColorBand *)bnode.storage;
|
const ColorBand *color_band = (const ColorBand *)bnode.storage;
|
||||||
builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
|
builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class CurveVecFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &bnode = builder.node();
|
const bNode &bnode = builder.node();
|
||||||
CurveMapping *cumap = (CurveMapping *)bnode.storage;
|
CurveMapping *cumap = (CurveMapping *)bnode.storage;
|
||||||
BKE_curvemapping_init(cumap);
|
BKE_curvemapping_init(cumap);
|
||||||
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
|
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
|
||||||
@@ -237,7 +237,7 @@ class CurveRGBFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &bnode = builder.node();
|
const bNode &bnode = builder.node();
|
||||||
CurveMapping *cumap = (CurveMapping *)bnode.storage;
|
CurveMapping *cumap = (CurveMapping *)bnode.storage;
|
||||||
BKE_curvemapping_init(cumap);
|
BKE_curvemapping_init(cumap);
|
||||||
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
|
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
|
||||||
@@ -356,7 +356,7 @@ class CurveFloatFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &bnode = builder.node();
|
const bNode &bnode = builder.node();
|
||||||
CurveMapping *cumap = (CurveMapping *)bnode.storage;
|
CurveMapping *cumap = (CurveMapping *)bnode.storage;
|
||||||
BKE_curvemapping_init(cumap);
|
BKE_curvemapping_init(cumap);
|
||||||
builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
|
builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ static int gpu_shader_math(GPUMaterial *mat,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const fn::MultiFunction *get_base_multi_function(bNode &node)
|
static const fn::MultiFunction *get_base_multi_function(const bNode &node)
|
||||||
{
|
{
|
||||||
const int mode = node.custom1;
|
const int mode = node.custom1;
|
||||||
const fn::MultiFunction *base_fn = nullptr;
|
const fn::MultiFunction *base_fn = nullptr;
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ class MixColorFunction : public fn::MultiFunction {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const fn::MultiFunction *get_multi_function(bNode &node)
|
static const fn::MultiFunction *get_multi_function(const bNode &node)
|
||||||
{
|
{
|
||||||
const NodeShaderMix *data = (NodeShaderMix *)node.storage;
|
const NodeShaderMix *data = (NodeShaderMix *)node.storage;
|
||||||
bool uniform_factor = data->factor_mode == NODE_MIX_MODE_UNIFORM;
|
bool uniform_factor = data->factor_mode == NODE_MIX_MODE_UNIFORM;
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ class MixRGBFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &node = builder.node();
|
const bNode &node = builder.node();
|
||||||
bool clamp = node.custom2 & SHD_MIXRGB_CLAMP;
|
bool clamp = node.custom2 & SHD_MIXRGB_CLAMP;
|
||||||
int mix_type = node.custom1;
|
int mix_type = node.custom1;
|
||||||
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
|
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ class BrickFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_brick_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_brick_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &node = builder.node();
|
const bNode &node = builder.node();
|
||||||
NodeTexBrick *tex = (NodeTexBrick *)node.storage;
|
NodeTexBrick *tex = (NodeTexBrick *)node.storage;
|
||||||
|
|
||||||
builder.construct_and_set_matching_fn<BrickFunction>(
|
builder.construct_and_set_matching_fn<BrickFunction>(
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ class GradientFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_gradient_tex_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_gradient_tex_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &node = builder.node();
|
const bNode &node = builder.node();
|
||||||
NodeTexGradient *tex = (NodeTexGradient *)node.storage;
|
NodeTexGradient *tex = (NodeTexGradient *)node.storage;
|
||||||
builder.construct_and_set_matching_fn<GradientFunction>(tex->gradient_type);
|
builder.construct_and_set_matching_fn<GradientFunction>(tex->gradient_type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ class MagicFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_magic_tex_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_magic_tex_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &node = builder.node();
|
const bNode &node = builder.node();
|
||||||
NodeTexMagic *tex = (NodeTexMagic *)node.storage;
|
NodeTexMagic *tex = (NodeTexMagic *)node.storage;
|
||||||
builder.construct_and_set_matching_fn<MagicFunction>(tex->depth);
|
builder.construct_and_set_matching_fn<MagicFunction>(tex->depth);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -516,7 +516,7 @@ class MusgraveFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_musgrave_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_musgrave_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &node = builder.node();
|
const bNode &node = builder.node();
|
||||||
NodeTexMusgrave *tex = (NodeTexMusgrave *)node.storage;
|
NodeTexMusgrave *tex = (NodeTexMusgrave *)node.storage;
|
||||||
builder.construct_and_set_matching_fn<MusgraveFunction>(tex->dimensions, tex->musgrave_type);
|
builder.construct_and_set_matching_fn<MusgraveFunction>(tex->dimensions, tex->musgrave_type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ class WaveFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_wave_tex_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_wave_tex_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &node = builder.node();
|
const bNode &node = builder.node();
|
||||||
NodeTexWave *tex = (NodeTexWave *)node.storage;
|
NodeTexWave *tex = (NodeTexWave *)node.storage;
|
||||||
builder.construct_and_set_matching_fn<WaveFunction>(
|
builder.construct_and_set_matching_fn<WaveFunction>(
|
||||||
tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile);
|
tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile);
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ class WhiteNoiseFunction : public fn::MultiFunction {
|
|||||||
|
|
||||||
static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder)
|
static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||||
{
|
{
|
||||||
bNode &node = builder.node();
|
const bNode &node = builder.node();
|
||||||
builder.construct_and_set_matching_fn<WhiteNoiseFunction>((int)node.custom1);
|
builder.construct_and_set_matching_fn<WhiteNoiseFunction>((int)node.custom1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const fn::MultiFunction *get_multi_function(bNode &node)
|
static const fn::MultiFunction *get_multi_function(const bNode &node)
|
||||||
{
|
{
|
||||||
NodeVectorMathOperation operation = NodeVectorMathOperation(node.custom1);
|
NodeVectorMathOperation operation = NodeVectorMathOperation(node.custom1);
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ static float3 sh_node_vector_rotate_euler(const float3 &vector,
|
|||||||
return result + center;
|
return result + center;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const fn::MultiFunction *get_multi_function(bNode &node)
|
static const fn::MultiFunction *get_multi_function(const bNode &node)
|
||||||
{
|
{
|
||||||
bool invert = node.custom2;
|
bool invert = node.custom2;
|
||||||
const int mode = node.custom1;
|
const int mode = node.custom1;
|
||||||
|
|||||||
Reference in New Issue
Block a user