1
1

Compare commits

...

38 Commits

Author SHA1 Message Date
e769961f32 order lines correctly 2021-03-04 18:18:50 +01:00
e8b29dab58 Merge branch 'master' into temp-derived-node-tree-refactor 2021-03-04 18:17:25 +01:00
d059fe522b cleanup 2021-03-04 18:06:56 +01:00
97156bbce5 rename files 2021-03-04 18:03:11 +01:00
2fb26211db rename new type to derived node tree 2021-03-04 18:01:49 +01:00
238b05ce30 Merge branch 'master' into temp-derived-node-tree-refactor 2021-03-04 17:54:36 +01:00
51d8c2ce75 fix building mf network 2021-03-04 17:14:35 +01:00
49049a3e6f simplify getting input values for socket 2021-03-04 16:55:44 +01:00
ee5952cf11 simplify naming 2021-03-04 16:41:19 +01:00
aa31d02b3b cleanup 2021-03-04 16:39:34 +01:00
1a778c2008 make node members private 2021-03-04 16:38:10 +01:00
7b6d8ff6dd simplify sockets 2021-03-04 16:33:33 +01:00
59a55de6f9 bring back support for muted nodes 2021-03-04 16:16:40 +01:00
4aa0105aac move function to xxx socket 2021-03-04 15:51:42 +01:00
65b892fa88 convert types from unlinked sockets 2021-03-04 15:42:29 +01:00
4780ea4bbd Merge branch 'master' into temp-derived-node-tree-refactor 2021-03-04 15:30:43 +01:00
2a879a4666 Merge branch 'master' into temp-derived-node-tree-refactor 2021-03-04 15:18:13 +01:00
4fbf19f3fd remove old derived node tree 2021-03-04 10:10:59 +01:00
3ed0843df9 remove all uses of old derived node tree 2021-03-04 10:08:42 +01:00
f94b3c886c remove remaining derived tree references from MOD_nodes.cc 2021-03-03 17:56:25 +01:00
ad5775452b Merge branch 'master' into temp-derived-node-tree-refactor 2021-03-03 16:37:55 +01:00
422901585b cleanup naming 2021-03-03 16:37:38 +01:00
940704beb3 remove unused function 2021-03-03 16:27:46 +01:00
a1653184c0 cleanup context 2021-03-03 16:24:05 +01:00
4658bd0342 cleanup 2021-03-03 16:12:08 +01:00
5d0b263c04 cleanup 2021-03-03 16:09:28 +01:00
30d71a7405 initial somewhat working function
Still does not work correctly with the pebbles demo file, because
the math nodes don't work yet.
2021-03-03 11:42:57 +01:00
0d15b30eb1 simplify importing types 2021-03-03 09:31:16 +01:00
1252f72606 prelude 2021-03-03 09:22:06 +01:00
0b0aba3cee support constructing context 2021-03-03 09:17:45 +01:00
3a64bed4e4 more constructors 2021-03-03 09:13:37 +01:00
1cd47ba37e operator bool 2021-03-03 09:03:56 +01:00
8986cb9ef8 more accessors 2021-03-03 09:01:30 +01:00
fd3d5ae32e add conversion/comparison operators and hash functions 2021-03-03 08:54:21 +01:00
a40b4d5439 construct contexts 2021-03-03 08:33:14 +01:00
a88e504fbd cleanup 2021-03-03 08:23:41 +01:00
cae115835f destructor 2021-03-03 08:17:49 +01:00
50fda06ef5 initial xxx node tree 2021-03-03 08:13:17 +01:00
13 changed files with 722 additions and 1257 deletions

View File

@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_float3.hh"
#include "BLI_function_ref.hh"
#include "BLI_listbase.h"
#include "BLI_set.hh"
#include "BLI_string.h"
@@ -77,6 +78,7 @@
#include "NOD_type_callbacks.hh"
using blender::float3;
using blender::FunctionRef;
using blender::IndexRange;
using blender::Map;
using blender::Set;
@@ -90,8 +92,8 @@ using blender::bke::PersistentObjectHandle;
using blender::fn::GMutablePointer;
using blender::fn::GValueMap;
using blender::nodes::GeoNodeExecParams;
using namespace blender::nodes::derived_node_tree_types;
using namespace blender::fn::multi_function_types;
using namespace blender::nodes::derived_node_tree_types;
static void initData(ModifierData *md)
{
@@ -254,8 +256,8 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
class GeometryNodesEvaluator {
private:
blender::LinearAllocator<> allocator_;
Map<std::pair<const DInputSocket *, const DOutputSocket *>, GMutablePointer> value_by_input_;
Vector<const DInputSocket *> group_outputs_;
Map<std::pair<DInputSocket, DOutputSocket>, GMutablePointer> value_by_input_;
Vector<DInputSocket> group_outputs_;
blender::nodes::MultiFunctionByNode &mf_by_node_;
const blender::nodes::DataTypeConversions &conversions_;
const PersistentDataHandleMap &handle_map_;
@@ -264,8 +266,8 @@ class GeometryNodesEvaluator {
Depsgraph *depsgraph_;
public:
GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data,
Vector<const DInputSocket *> group_outputs,
GeometryNodesEvaluator(const Map<DOutputSocket, GMutablePointer> &group_input_data,
Vector<DInputSocket> group_outputs,
blender::nodes::MultiFunctionByNode &mf_by_node,
const PersistentDataHandleMap &handle_map,
const Object *self_object,
@@ -280,15 +282,15 @@ class GeometryNodesEvaluator {
depsgraph_(depsgraph)
{
for (auto item : group_input_data.items()) {
this->forward_to_inputs(*item.key, item.value);
this->forward_to_inputs(item.key, item.value);
}
}
Vector<GMutablePointer> execute()
{
Vector<GMutablePointer> results;
for (const DInputSocket *group_output : group_outputs_) {
Vector<GMutablePointer> result = this->get_input_values(*group_output);
for (const DInputSocket &group_output : group_outputs_) {
Vector<GMutablePointer> result = this->get_input_values(group_output);
results.append(result[0]);
}
for (GMutablePointer value : value_by_input_.values()) {
@@ -298,62 +300,63 @@ class GeometryNodesEvaluator {
}
private:
Vector<GMutablePointer> get_input_values(const DInputSocket &socket_to_compute)
Vector<GMutablePointer> get_input_values(const DInputSocket socket_to_compute)
{
Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets();
Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs();
const int total_inputs = from_sockets.size() + from_group_inputs.size();
if (total_inputs == 0) {
/* The input is not connected, use the value from the socket itself. */
return {get_unlinked_input_value(socket_to_compute)};
}
if (from_group_inputs.size() == 1) {
return {get_unlinked_input_value(socket_to_compute)};
}
Vector<DSocket> from_sockets;
socket_to_compute.foreach_origin_socket([&](DSocket socket) { from_sockets.append(socket); });
/* Multi-input sockets contain a vector of inputs. */
if (socket_to_compute.is_multi_input_socket()) {
if (socket_to_compute->is_multi_input_socket()) {
Vector<GMutablePointer> values;
for (const DOutputSocket *from_socket : from_sockets) {
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
&socket_to_compute, from_socket);
std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
if (value.has_value()) {
values.append(*value);
}
else {
this->compute_output_and_forward(*from_socket);
GMutablePointer value = value_by_input_.pop(key);
values.append(value);
}
for (const DSocket from_socket : from_sockets) {
GMutablePointer value = get_input_from_incoming_link(socket_to_compute, from_socket);
values.append(value);
}
return values;
}
const DOutputSocket &from_socket = *from_sockets[0];
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
&socket_to_compute, &from_socket);
std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
if (value.has_value()) {
/* This input has been computed before, return it directly. */
return {*value};
if (from_sockets.is_empty()) {
/* The input is not connected, use the value from the socket itself. */
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
return {get_unlinked_input_value(socket_to_compute, type)};
}
/* Compute the socket now. */
this->compute_output_and_forward(from_socket);
return {value_by_input_.pop(key)};
const DSocket from_socket = from_sockets[0];
GMutablePointer value = this->get_input_from_incoming_link(socket_to_compute, from_socket);
return {value};
}
void compute_output_and_forward(const DOutputSocket &socket_to_compute)
GMutablePointer get_input_from_incoming_link(const DInputSocket socket_to_compute,
const DSocket from_socket)
{
const DNode &node = socket_to_compute.node();
if (from_socket->is_output()) {
const DOutputSocket from_output_socket{from_socket};
const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(socket_to_compute,
from_output_socket);
std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
if (value.has_value()) {
/* This input has been computed before, return it directly. */
return {*value};
}
if (!socket_to_compute.is_available()) {
/* Compute the socket now. */
this->compute_output_and_forward(from_output_socket);
return {value_by_input_.pop(key)};
}
/* Get value from an unlinked input socket. */
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
const DInputSocket from_input_socket{from_socket};
return {get_unlinked_input_value(from_input_socket, type)};
}
void compute_output_and_forward(const DOutputSocket socket_to_compute)
{
const DNode node{socket_to_compute.context(), &socket_to_compute->node()};
if (!socket_to_compute->is_available()) {
/* If the output is not available, use a default value. */
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute.typeinfo());
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
type.copy_to_uninitialized(type.default_value(), buffer);
this->forward_to_inputs(socket_to_compute, {type, buffer});
@@ -362,9 +365,9 @@ class GeometryNodesEvaluator {
/* Prepare inputs required to execute the node. */
GValueMap<StringRef> node_inputs_map{allocator_};
for (const DInputSocket *input_socket : node.inputs()) {
for (const InputSocketRef *input_socket : node->inputs()) {
if (input_socket->is_available()) {
Vector<GMutablePointer> values = this->get_input_values(*input_socket);
Vector<GMutablePointer> values = this->get_input_values({node.context(), input_socket});
for (int i = 0; i < values.size(); ++i) {
/* Values from Multi Input Sockets are stored in input map with the format
* <identifier>[<index>]. */
@@ -382,15 +385,15 @@ class GeometryNodesEvaluator {
this->execute_node(node, params);
/* Forward computed outputs to linked input sockets. */
for (const DOutputSocket *output_socket : node.outputs()) {
for (const OutputSocketRef *output_socket : node->outputs()) {
if (output_socket->is_available()) {
GMutablePointer value = node_outputs_map.extract(output_socket->identifier());
this->forward_to_inputs(*output_socket, value);
this->forward_to_inputs({node.context(), output_socket}, value);
}
}
}
void execute_node(const DNode &node, GeoNodeExecParams params)
void execute_node(const DNode node, GeoNodeExecParams params)
{
const bNode &bnode = params.node();
@@ -403,7 +406,7 @@ class GeometryNodesEvaluator {
}
/* Use the multi-function implementation if it exists. */
const MultiFunction *multi_function = mf_by_node_.lookup_default(&node, nullptr);
const MultiFunction *multi_function = mf_by_node_.lookup_default(node, nullptr);
if (multi_function != nullptr) {
this->execute_multi_function_node(node, params, *multi_function);
return;
@@ -413,51 +416,52 @@ class GeometryNodesEvaluator {
this->execute_unknown_node(node, params);
}
void store_ui_hints(const DNode &node, GeoNodeExecParams params) const
void store_ui_hints(const DNode node, GeoNodeExecParams params) const
{
for (const DInputSocket *dsocket : node.inputs()) {
if (!dsocket->is_available()) {
for (const InputSocketRef *socket_ref : node->inputs()) {
if (!socket_ref->is_available()) {
continue;
}
if (dsocket->bsocket()->type != SOCK_GEOMETRY) {
if (socket_ref->bsocket()->type != SOCK_GEOMETRY) {
continue;
}
bNodeTree *btree_cow = node.node_ref().tree().btree();
bNodeTree *btree_cow = node->btree();
bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
const NodeTreeEvaluationContext context(*self_object_, *modifier_);
const GeometrySet &geometry_set = params.get_input<GeometrySet>(dsocket->identifier());
const GeometrySet &geometry_set = params.get_input<GeometrySet>(socket_ref->identifier());
const Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
for (const GeometryComponent *component : components) {
component->attribute_foreach([&](StringRefNull attribute_name,
const AttributeMetaData &UNUSED(meta_data)) {
BKE_nodetree_attribute_hint_add(*btree_original, context, *node.bnode(), attribute_name);
return true;
});
component->attribute_foreach(
[&](StringRefNull attribute_name, const AttributeMetaData &UNUSED(meta_data)) {
BKE_nodetree_attribute_hint_add(
*btree_original, context, *node->bnode(), attribute_name);
return true;
});
}
}
}
void execute_multi_function_node(const DNode &node,
void execute_multi_function_node(const DNode node,
GeoNodeExecParams params,
const MultiFunction &fn)
{
MFContextBuilder fn_context;
MFParamsBuilder fn_params{fn, 1};
Vector<GMutablePointer> input_data;
for (const DInputSocket *dsocket : node.inputs()) {
if (dsocket->is_available()) {
GMutablePointer data = params.extract_input(dsocket->identifier());
for (const InputSocketRef *socket_ref : node->inputs()) {
if (socket_ref->is_available()) {
GMutablePointer data = params.extract_input(socket_ref->identifier());
fn_params.add_readonly_single_input(GSpan(*data.type(), data.get(), 1));
input_data.append(data);
}
}
Vector<GMutablePointer> output_data;
for (const DOutputSocket *dsocket : node.outputs()) {
if (dsocket->is_available()) {
const CPPType &type = *blender::nodes::socket_cpp_type_get(*dsocket->typeinfo());
for (const OutputSocketRef *socket_ref : node->outputs()) {
if (socket_ref->is_available()) {
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_ref->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
fn_params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1));
output_data.append(GMutablePointer(type, buffer));
@@ -468,19 +472,19 @@ class GeometryNodesEvaluator {
value.destruct();
}
int output_index = 0;
for (const int i : node.outputs().index_range()) {
if (node.output(i).is_available()) {
for (const int i : node->outputs().index_range()) {
if (node->output(i).is_available()) {
GMutablePointer value = output_data[output_index];
params.set_output_by_move(node.output(i).identifier(), value);
params.set_output_by_move(node->output(i).identifier(), value);
value.destruct();
output_index++;
}
}
}
void execute_unknown_node(const DNode &node, GeoNodeExecParams params)
void execute_unknown_node(const DNode node, GeoNodeExecParams params)
{
for (const DOutputSocket *socket : node.outputs()) {
for (const OutputSocketRef *socket : node->outputs()) {
if (socket->is_available()) {
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
params.set_output_by_copy(socket->identifier(), {type, type.default_value()});
@@ -488,17 +492,18 @@ class GeometryNodesEvaluator {
}
}
void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward)
void forward_to_inputs(const DOutputSocket from_socket, GMutablePointer value_to_forward)
{
/* For all sockets that are linked with the from_socket push the value to their node. */
Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets();
Vector<DInputSocket> to_sockets_all;
from_socket.foreach_target_socket(
[&](DInputSocket to_socket) { to_sockets_all.append(to_socket); });
const CPPType &from_type = *value_to_forward.type();
Vector<const DInputSocket *> to_sockets_same_type;
for (const DInputSocket *to_socket : to_sockets_all) {
Vector<DInputSocket> to_sockets_same_type;
for (const DInputSocket &to_socket : to_sockets_all) {
const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo());
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
to_socket, &from_socket);
const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
if (from_type == to_type) {
to_sockets_same_type.append(to_socket);
}
@@ -520,23 +525,21 @@ class GeometryNodesEvaluator {
}
else if (to_sockets_same_type.size() == 1) {
/* This value is only used on one input socket, no need to copy it. */
const DInputSocket *to_socket = to_sockets_same_type[0];
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
to_socket, &from_socket);
const DInputSocket to_socket = to_sockets_same_type[0];
const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
add_value_to_input_socket(key, value_to_forward);
}
else {
/* Multiple inputs use the value, make a copy for every input except for one. */
const DInputSocket *first_to_socket = to_sockets_same_type[0];
Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
const DInputSocket first_to_socket = to_sockets_same_type[0];
Span<DInputSocket> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
const CPPType &type = *value_to_forward.type();
const std::pair<const DInputSocket *, const DOutputSocket *> first_key = std::make_pair(
first_to_socket, &from_socket);
const std::pair<DInputSocket, DOutputSocket> first_key = std::make_pair(first_to_socket,
from_socket);
add_value_to_input_socket(first_key, value_to_forward);
for (const DInputSocket *to_socket : other_to_sockets) {
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
to_socket, &from_socket);
for (const DInputSocket &to_socket : other_to_sockets) {
const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
void *buffer = allocator_.allocate(type.size(), type.alignment());
type.copy_to_uninitialized(value_to_forward.get(), buffer);
add_value_to_input_socket(key, GMutablePointer{type, buffer});
@@ -544,22 +547,17 @@ class GeometryNodesEvaluator {
}
}
void add_value_to_input_socket(const std::pair<const DInputSocket *, const DOutputSocket *> key,
void add_value_to_input_socket(const std::pair<DInputSocket, DOutputSocket> key,
GMutablePointer value)
{
value_by_input_.add_new(key, value);
}
GMutablePointer get_unlinked_input_value(const DInputSocket &socket)
GMutablePointer get_unlinked_input_value(const DInputSocket &socket,
const CPPType &required_type)
{
bNodeSocket *bsocket;
if (socket.linked_group_inputs().size() == 0) {
bsocket = socket.bsocket();
}
else {
bsocket = socket.linked_group_inputs()[0]->bsocket();
}
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket.typeinfo());
bNodeSocket *bsocket = socket->bsocket();
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
if (bsocket->type == SOCK_OBJECT) {
@@ -576,7 +574,19 @@ class GeometryNodesEvaluator {
blender::nodes::socket_cpp_value_get(*bsocket, buffer);
}
return {type, buffer};
if (type == required_type) {
return {type, buffer};
}
if (conversions_.is_convertible(type, required_type)) {
void *converted_buffer = allocator_.allocate(required_type.size(),
required_type.alignment());
conversions_.convert(type, required_type, buffer, converted_buffer);
type.destruct(buffer);
return {required_type, converted_buffer};
}
void *default_buffer = allocator_.allocate(required_type.size(), required_type.alignment());
type.copy_to_uninitialized(type.default_value(), default_buffer);
return {required_type, default_buffer};
}
};
@@ -985,7 +995,7 @@ static void fill_data_handle_map(const NodesModifierSettings &settings,
{
Set<ID *> used_ids;
find_used_ids_from_settings(settings, used_ids);
find_used_ids_from_nodes(*tree.btree(), used_ids);
find_used_ids_from_nodes(*tree.root_context().tree().btree(), used_ids);
int current_handle = 0;
for (ID *id : used_ids) {
@@ -1013,8 +1023,8 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree
* often than necessary. It's going to be replaced soon.
*/
static GeometrySet compute_geometry(const DerivedNodeTree &tree,
Span<const DOutputSocket *> group_input_sockets,
const DInputSocket &socket_to_compute,
Span<const OutputSocketRef *> group_input_sockets,
const InputSocketRef &socket_to_compute,
GeometrySet input_geometry_set,
NodesModifierData *nmd,
const ModifierEvalContext *ctx)
@@ -1026,32 +1036,33 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
PersistentDataHandleMap handle_map;
fill_data_handle_map(nmd->settings, tree, handle_map);
Map<const DOutputSocket *, GMutablePointer> group_inputs;
Map<DOutputSocket, GMutablePointer> group_inputs;
const DTreeContext *root_context = &tree.root_context();
if (group_input_sockets.size() > 0) {
Span<const DOutputSocket *> remaining_input_sockets = group_input_sockets;
Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets;
/* If the group expects a geometry as first input, use the geometry that has been passed to
* modifier. */
const DOutputSocket *first_input_socket = group_input_sockets[0];
const OutputSocketRef *first_input_socket = group_input_sockets[0];
if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) {
GeometrySet *geometry_set_in = allocator.construct<GeometrySet>(
std::move(input_geometry_set));
group_inputs.add_new(first_input_socket, geometry_set_in);
group_inputs.add_new({root_context, first_input_socket}, geometry_set_in);
remaining_input_sockets = remaining_input_sockets.drop_front(1);
}
/* Initialize remaining group inputs. */
for (const DOutputSocket *socket : remaining_input_sockets) {
for (const OutputSocketRef *socket : remaining_input_sockets) {
const CPPType &cpp_type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
initialize_group_input(*nmd, handle_map, *socket->bsocket(), cpp_type, value_in);
group_inputs.add_new(socket, {cpp_type, value_in});
group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
}
}
Vector<const DInputSocket *> group_outputs;
group_outputs.append(&socket_to_compute);
Vector<DInputSocket> group_outputs;
group_outputs.append({root_context, &socket_to_compute});
GeometryNodesEvaluator evaluator{group_inputs,
group_outputs,
@@ -1126,16 +1137,17 @@ static void modifyGeometry(ModifierData *md,
check_property_socket_sync(ctx->object, md);
blender::nodes::NodeTreeRefMap tree_refs;
DerivedNodeTree tree{nmd->node_group, tree_refs};
NodeTreeRefMap tree_refs;
DerivedNodeTree tree{*nmd->node_group, tree_refs};
if (tree.has_link_cycles()) {
BKE_modifier_set_error(ctx->object, md, "Node group has cycles");
return;
}
Span<const DNode *> input_nodes = tree.nodes_by_type("NodeGroupInput");
Span<const DNode *> output_nodes = tree.nodes_by_type("NodeGroupOutput");
const NodeTreeRef &root_tree_ref = tree.root_context().tree();
Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput");
Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput");
if (input_nodes.size() > 1) {
return;
@@ -1144,16 +1156,18 @@ static void modifyGeometry(ModifierData *md,
return;
}
Span<const DOutputSocket *> group_inputs = (input_nodes.size() == 1) ?
input_nodes[0]->outputs().drop_back(1) :
Span<const DOutputSocket *>{};
Span<const DInputSocket *> group_outputs = output_nodes[0]->inputs().drop_back(1);
Span<const OutputSocketRef *> group_inputs;
if (input_nodes.size() == 1) {
group_inputs = input_nodes[0]->outputs().drop_back(1);
}
Span<const InputSocketRef *> group_outputs = output_nodes[0]->inputs().drop_back(1);
if (group_outputs.size() == 0) {
return;
}
const DInputSocket *group_output = group_outputs[0];
const InputSocketRef *group_output = group_outputs[0];
if (group_output->idname() != "NodeSocketGeometry") {
return;
}

View File

@@ -16,547 +16,332 @@
#pragma once
/** \file
* \ingroup nodes
*
* DerivedNodeTree provides a flattened view on a bNodeTree, i.e. node groups are inlined. It
* builds on top of NodeTreeRef and supports similar queries efficiently.
*
* Every inlined node remembers its path to the parent ("call stack").
*
* Unlinked group node inputs are handled separately from other sockets.
*
* There is a dot graph exporter for debugging purposes.
*/
#include "BLI_function_ref.hh"
#include "BLI_vector_set.hh"
#include "NOD_node_tree_ref.hh"
#include "BLI_vector_set.hh"
namespace blender::nodes {
class DSocket;
class DInputSocket;
class DOutputSocket;
class DNode;
class DParentNode;
class DGroupInput;
class DTreeContext;
class DerivedNodeTree;
class DSocket : NonCopyable, NonMovable {
protected:
DNode *node_;
const SocketRef *socket_ref_;
int id_;
struct DNode;
struct DSocket;
struct DInputSocket;
struct DOutputSocket;
class DTreeContext {
private:
DTreeContext *parent_context_;
const NodeRef *parent_node_;
const NodeTreeRef *tree_;
Map<const NodeRef *, DTreeContext *> children_;
friend DerivedNodeTree;
public:
const DNode &node() const;
const NodeTreeRef &tree() const;
const DTreeContext *parent_context() const;
const NodeRef *parent_node() const;
const DTreeContext *child_context(const NodeRef &node) const;
bool is_root() const;
};
int id() const;
int index() const;
class DNode {
private:
const DTreeContext *context_ = nullptr;
const NodeRef *node_ref_ = nullptr;
bool is_input() const;
bool is_output() const;
public:
DNode() = default;
DNode(const DTreeContext *context, const NodeRef *node);
const DSocket &as_base() const;
const DInputSocket &as_input() const;
const DOutputSocket &as_output() const;
const DTreeContext *context() const;
const NodeRef *node_ref() const;
const NodeRef *operator->() const;
PointerRNA *rna() const;
StringRefNull idname() const;
StringRefNull name() const;
StringRefNull identifier() const;
bNodeSocketType *typeinfo() const;
friend bool operator==(const DNode &a, const DNode &b);
friend bool operator!=(const DNode &a, const DNode &b);
operator bool() const;
const SocketRef &socket_ref() const;
bNodeSocket *bsocket() const;
uint64_t hash() const;
};
bool is_available() const;
class DSocket {
protected:
const DTreeContext *context_ = nullptr;
const SocketRef *socket_ref_ = nullptr;
public:
DSocket() = default;
DSocket(const DTreeContext *context, const SocketRef *socket);
DSocket(const DInputSocket &input_socket);
DSocket(const DOutputSocket &output_socket);
const DTreeContext *context() const;
const SocketRef *socket_ref() const;
const SocketRef *operator->() const;
friend bool operator==(const DSocket &a, const DSocket &b);
friend bool operator!=(const DSocket &a, const DSocket &b);
operator bool() const;
uint64_t hash() const;
};
class DInputSocket : public DSocket {
private:
Vector<DOutputSocket *> linked_sockets_;
Vector<DGroupInput *> linked_group_inputs_;
bool is_multi_input_socket_;
friend DerivedNodeTree;
public:
const InputSocketRef &socket_ref() const;
DInputSocket() = default;
DInputSocket(const DTreeContext *context, const InputSocketRef *socket);
explicit DInputSocket(const DSocket &base_socket);
Span<const DOutputSocket *> linked_sockets() const;
Span<const DGroupInput *> linked_group_inputs() const;
const InputSocketRef *socket_ref() const;
const InputSocketRef *operator->() const;
bool is_linked() const;
bool is_multi_input_socket() const;
DOutputSocket get_corresponding_group_node_output() const;
DOutputSocket get_corresponding_group_input_socket() const;
void foreach_origin_socket(FunctionRef<void(DSocket)> callback) const;
};
class DOutputSocket : public DSocket {
private:
Vector<DInputSocket *> linked_sockets_;
friend DerivedNodeTree;
public:
const OutputSocketRef &socket_ref() const;
Span<const DInputSocket *> linked_sockets() const;
DOutputSocket() = default;
DOutputSocket(const DTreeContext *context, const OutputSocketRef *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_output_socket() const;
void foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const;
};
class DGroupInput : NonCopyable, NonMovable {
private:
const InputSocketRef *socket_ref_;
DParentNode *parent_;
Vector<DInputSocket *> linked_sockets_;
int id_;
friend DerivedNodeTree;
public:
const InputSocketRef &socket_ref() const;
bNodeSocket *bsocket() const;
const DParentNode *parent() const;
Span<const DInputSocket *> linked_sockets() const;
int id() const;
StringRefNull name() const;
};
class DNode : NonCopyable, NonMovable {
private:
const NodeRef *node_ref_;
DParentNode *parent_;
Span<DInputSocket *> inputs_;
Span<DOutputSocket *> outputs_;
int id_;
friend DerivedNodeTree;
public:
const NodeRef &node_ref() const;
const DParentNode *parent() const;
Span<const DInputSocket *> inputs() const;
Span<const DOutputSocket *> outputs() const;
const DInputSocket &input(int index) const;
const DOutputSocket &output(int index) const;
const DInputSocket &input(int index, StringRef expected_name) const;
const DOutputSocket &output(int index, StringRef expected_name) const;
int id() const;
PointerRNA *rna() const;
StringRefNull idname() const;
StringRefNull name() const;
bNode *bnode() const;
bNodeType *typeinfo() const;
private:
void destruct_with_sockets();
};
class DParentNode : NonCopyable, NonMovable {
private:
const NodeRef *node_ref_;
DParentNode *parent_;
int id_;
friend DerivedNodeTree;
public:
const DParentNode *parent() const;
const NodeRef &node_ref() const;
int id() const;
};
class DerivedNodeTree : NonCopyable, NonMovable {
class DerivedNodeTree {
private:
LinearAllocator<> allocator_;
Vector<DNode *> nodes_by_id_;
Vector<DGroupInput *> group_inputs_;
Vector<DParentNode *> parent_nodes_;
Vector<DSocket *> sockets_by_id_;
Vector<DInputSocket *> input_sockets_;
Vector<DOutputSocket *> output_sockets_;
MultiValueMap<const bNodeType *, DNode *> nodes_by_type_;
DTreeContext *root_context_;
VectorSet<const NodeTreeRef *> used_node_tree_refs_;
bNodeTree *btree_;
public:
DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs);
DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs);
~DerivedNodeTree();
bNodeTree *btree() const;
Span<const DNode *> nodes() const;
Span<const DNode *> nodes_by_type(StringRefNull idname) const;
Span<const DNode *> nodes_by_type(const bNodeType *nodetype) const;
Span<const DSocket *> sockets() const;
Span<const DInputSocket *> input_sockets() const;
Span<const DOutputSocket *> output_sockets() const;
Span<const DGroupInput *> group_inputs() const;
const DTreeContext &root_context() const;
Span<const NodeTreeRef *> used_node_tree_refs() const;
bool has_link_cycles() const;
std::string to_dot() const;
void foreach_node(FunctionRef<void(DNode)> callback) const;
private:
/* Utility functions used during construction. */
void insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref,
DParentNode *parent,
Vector<DNode *> &all_nodes);
DNode &create_node(const NodeRef &node_ref,
DParentNode *parent,
MutableSpan<DSocket *> r_sockets_map);
void expand_groups(Vector<DNode *> &all_nodes,
Vector<DGroupInput *> &all_group_inputs,
Vector<DParentNode *> &all_parent_nodes,
NodeTreeRefMap &node_tree_refs);
void expand_group_node(DNode &group_node,
Vector<DNode *> &all_nodes,
Vector<DGroupInput *> &all_group_inputs,
Vector<DParentNode *> &all_parent_nodes,
NodeTreeRefMap &node_tree_refs);
void create_group_inputs_for_unlinked_inputs(DNode &node,
Vector<DGroupInput *> &all_group_inputs);
void relink_group_inputs(const NodeTreeRef &group_ref,
Span<DNode *> nodes_by_id,
DNode &group_node);
void relink_group_outputs(const NodeTreeRef &group_ref,
Span<DNode *> nodes_by_id,
DNode &group_node);
void remove_expanded_group_interfaces(Vector<DNode *> &all_nodes);
void remove_unused_group_inputs(Vector<DGroupInput *> &all_group_inputs);
void relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes);
void relink_muted_node(DNode &muted_node);
void store_in_this_and_init_ids(Vector<DNode *> &&all_nodes,
Vector<DGroupInput *> &&all_group_inputs,
Vector<DParentNode *> &&all_parent_nodes);
DTreeContext &construct_context_recursively(DTreeContext *parent_context,
const NodeRef *parent_node,
bNodeTree &btree,
NodeTreeRefMap &node_tree_refs);
void destruct_context_recursively(DTreeContext *context);
void foreach_node_in_context_recursive(const DTreeContext &context,
FunctionRef<void(DNode)> callback) const;
};
namespace derived_node_tree_types {
using namespace node_tree_ref_types;
using nodes::DerivedNodeTree;
using nodes::DGroupInput;
using nodes::DInputSocket;
using nodes::DNode;
using nodes::DOutputSocket;
using nodes::DParentNode;
}; // namespace derived_node_tree_types
using nodes::DSocket;
using nodes::DTreeContext;
} // namespace derived_node_tree_types
/* --------------------------------------------------------------------
* DSocket inline methods.
* DTreeContext inline methods.
*/
inline const DNode &DSocket::node() const
inline const NodeTreeRef &DTreeContext::tree() const
{
return *node_;
return *tree_;
}
inline int DSocket::id() const
inline const DTreeContext *DTreeContext::parent_context() const
{
return id_;
return parent_context_;
}
inline int DSocket::index() const
inline const NodeRef *DTreeContext::parent_node() const
{
return socket_ref_->index();
return parent_node_;
}
inline bool DSocket::is_input() const
inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const
{
return socket_ref_->is_input();
return children_.lookup_default(&node, nullptr);
}
inline bool DSocket::is_output() const
inline bool DTreeContext::is_root() const
{
return socket_ref_->is_output();
}
inline const DSocket &DSocket::as_base() const
{
return *this;
}
inline const DInputSocket &DSocket::as_input() const
{
return static_cast<const DInputSocket &>(*this);
}
inline const DOutputSocket &DSocket::as_output() const
{
return static_cast<const DOutputSocket &>(*this);
}
inline PointerRNA *DSocket::rna() const
{
return socket_ref_->rna();
}
inline StringRefNull DSocket::idname() const
{
return socket_ref_->idname();
}
inline StringRefNull DSocket::name() const
{
return socket_ref_->name();
}
inline StringRefNull DSocket::identifier() const
{
return socket_ref_->identifier();
}
inline bNodeSocketType *DSocket::typeinfo() const
{
return socket_ref_->bsocket()->typeinfo;
}
inline const SocketRef &DSocket::socket_ref() const
{
return *socket_ref_;
}
inline bNodeSocket *DSocket::bsocket() const
{
return socket_ref_->bsocket();
}
inline bool DSocket::is_available() const
{
return (socket_ref_->bsocket()->flag & SOCK_UNAVAIL) == 0;
}
/* --------------------------------------------------------------------
* DInputSocket inline methods.
*/
inline const InputSocketRef &DInputSocket::socket_ref() const
{
return socket_ref_->as_input();
}
inline Span<const DOutputSocket *> DInputSocket::linked_sockets() const
{
return linked_sockets_;
}
inline Span<const DGroupInput *> DInputSocket::linked_group_inputs() const
{
return linked_group_inputs_;
}
inline bool DInputSocket::is_linked() const
{
return linked_sockets_.size() > 0 || linked_group_inputs_.size() > 0;
}
inline bool DInputSocket::is_multi_input_socket() const
{
return is_multi_input_socket_;
}
/* --------------------------------------------------------------------
* DOutputSocket inline methods.
*/
inline const OutputSocketRef &DOutputSocket::socket_ref() const
{
return socket_ref_->as_output();
}
inline Span<const DInputSocket *> DOutputSocket::linked_sockets() const
{
return linked_sockets_;
}
/* --------------------------------------------------------------------
* DGroupInput inline methods.
*/
inline const InputSocketRef &DGroupInput::socket_ref() const
{
return *socket_ref_;
}
inline bNodeSocket *DGroupInput::bsocket() const
{
return socket_ref_->bsocket();
}
inline const DParentNode *DGroupInput::parent() const
{
return parent_;
}
inline Span<const DInputSocket *> DGroupInput::linked_sockets() const
{
return linked_sockets_;
}
inline int DGroupInput::id() const
{
return id_;
}
inline StringRefNull DGroupInput::name() const
{
return socket_ref_->name();
return parent_context_ == nullptr;
}
/* --------------------------------------------------------------------
* DNode inline methods.
*/
inline const NodeRef &DNode::node_ref() const
inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref)
: context_(context), node_ref_(node_ref)
{
return *node_ref_;
BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree());
}
inline const DParentNode *DNode::parent() const
inline const DTreeContext *DNode::context() const
{
return parent_;
return context_;
}
inline Span<const DInputSocket *> DNode::inputs() const
inline const NodeRef *DNode::node_ref() const
{
return inputs_;
return node_ref_;
}
inline Span<const DOutputSocket *> DNode::outputs() const
inline bool operator==(const DNode &a, const DNode &b)
{
return outputs_;
return a.context_ == b.context_ && a.node_ref_ == b.node_ref_;
}
inline const DInputSocket &DNode::input(int index) const
inline bool operator!=(const DNode &a, const DNode &b)
{
return *inputs_[index];
return !(a == b);
}
inline const DOutputSocket &DNode::output(int index) const
inline DNode::operator bool() const
{
return *outputs_[index];
return node_ref_ != nullptr;
}
inline const DInputSocket &DNode::input(int index, StringRef expected_name) const
inline const NodeRef *DNode::operator->() const
{
const DInputSocket &socket = *inputs_[index];
BLI_assert(socket.name() == expected_name);
UNUSED_VARS_NDEBUG(expected_name);
return socket;
return node_ref_;
}
inline const DOutputSocket &DNode::output(int index, StringRef expected_name) const
inline uint64_t DNode::hash() const
{
const DOutputSocket &socket = *outputs_[index];
BLI_assert(socket.name() == expected_name);
UNUSED_VARS_NDEBUG(expected_name);
return socket;
}
inline int DNode::id() const
{
return id_;
}
inline PointerRNA *DNode::rna() const
{
return node_ref_->rna();
}
inline StringRefNull DNode::idname() const
{
return node_ref_->idname();
}
inline StringRefNull DNode::name() const
{
return node_ref_->name();
}
inline bNode *DNode::bnode() const
{
return node_ref_->bnode();
}
inline bNodeType *DNode::typeinfo() const
{
return node_ref_->bnode()->typeinfo;
return DefaultHash<const DTreeContext *>{}(context_) ^ DefaultHash<const NodeRef *>{}(node_ref_);
}
/* --------------------------------------------------------------------
* DParentNode inline methods.
* DSocket inline methods.
*/
inline const DParentNode *DParentNode::parent() const
inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref)
: context_(context), socket_ref_(socket_ref)
{
return parent_;
BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree());
}
inline const NodeRef &DParentNode::node_ref() const
inline DSocket::DSocket(const DInputSocket &input_socket)
: DSocket(input_socket.context_, input_socket.socket_ref_)
{
return *node_ref_;
}
inline int DParentNode::id() const
inline DSocket::DSocket(const DOutputSocket &output_socket)
: DSocket(output_socket.context_, output_socket.socket_ref_)
{
return id_;
}
inline const DTreeContext *DSocket::context() const
{
return context_;
}
inline const SocketRef *DSocket::socket_ref() const
{
return socket_ref_;
}
inline bool operator==(const DSocket &a, const DSocket &b)
{
return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_;
}
inline bool operator!=(const DSocket &a, const DSocket &b)
{
return !(a == b);
}
inline DSocket::operator bool() const
{
return socket_ref_ != nullptr;
}
inline const SocketRef *DSocket::operator->() const
{
return socket_ref_;
}
inline uint64_t DSocket::hash() const
{
return DefaultHash<const DTreeContext *>{}(context_) ^
DefaultHash<const SocketRef *>{}(socket_ref_);
}
/* --------------------------------------------------------------------
* DInputSocket inline methods.
*/
inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref)
: DSocket(context, socket_ref)
{
}
inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_socket)
{
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_;
}
/* --------------------------------------------------------------------
* DOutputSocket inline methods.
*/
inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref)
: DSocket(context, socket_ref)
{
}
inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_socket)
{
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_;
}
/* --------------------------------------------------------------------
* DerivedNodeTree inline methods.
*/
inline bNodeTree *DerivedNodeTree::btree() const
inline const DTreeContext &DerivedNodeTree::root_context() const
{
return btree_;
}
inline Span<const DNode *> DerivedNodeTree::nodes() const
{
return nodes_by_id_;
}
inline Span<const DNode *> DerivedNodeTree::nodes_by_type(StringRefNull idname) const
{
const bNodeType *nodetype = nodeTypeFind(idname.c_str());
return this->nodes_by_type(nodetype);
}
inline Span<const DNode *> DerivedNodeTree::nodes_by_type(const bNodeType *nodetype) const
{
return nodes_by_type_.lookup(nodetype);
}
inline Span<const DSocket *> DerivedNodeTree::sockets() const
{
return sockets_by_id_;
}
inline Span<const DInputSocket *> DerivedNodeTree::input_sockets() const
{
return input_sockets_;
}
inline Span<const DOutputSocket *> DerivedNodeTree::output_sockets() const
{
return output_sockets_;
}
inline Span<const DGroupInput *> DerivedNodeTree::group_inputs() const
{
return group_inputs_;
return *root_context_;
}
inline Span<const NodeTreeRef *> DerivedNodeTree::used_node_tree_refs() const

View File

@@ -59,7 +59,7 @@ using fn::GValueMap;
class GeoNodeExecParams {
private:
const DNode &node_;
const DNode node_;
GValueMap<StringRef> &input_values_;
GValueMap<StringRef> &output_values_;
const PersistentDataHandleMap &handle_map_;
@@ -68,7 +68,7 @@ class GeoNodeExecParams {
Depsgraph *depsgraph_;
public:
GeoNodeExecParams(const DNode &node,
GeoNodeExecParams(const DNode node,
GValueMap<StringRef> &input_values,
GValueMap<StringRef> &output_values,
const PersistentDataHandleMap &handle_map,
@@ -182,7 +182,7 @@ class GeoNodeExecParams {
*/
const bNode &node() const
{
return *node_.bnode();
return *node_->bnode();
}
const PersistentDataHandleMap &handle_map() const

View File

@@ -28,14 +28,15 @@
#include "NOD_derived_node_tree.hh"
#include "NOD_type_callbacks.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_resource_collector.hh"
namespace blender::nodes {
/**
* A MFNetworkTreeMap maps various components of a DerivedNodeTree to components of a
* fn::MFNetwork. This is necessary for further processing of a multi-function network that has
* been generated from a node tree.
* A MFNetworkTreeMap maps various components of a node tree to components of a fn::MFNetwork. This
* is necessary for further processing of a multi-function network that has been generated from a
* node tree.
*/
class MFNetworkTreeMap {
private:
@@ -47,15 +48,11 @@ class MFNetworkTreeMap {
*/
const DerivedNodeTree &tree_;
fn::MFNetwork &network_;
Array<Vector<fn::MFSocket *, 1>> sockets_by_dsocket_id_;
Array<fn::MFOutputSocket *> socket_by_group_input_id_;
MultiValueMap<DSocket, fn::MFSocket *> sockets_by_dsocket_;
public:
MFNetworkTreeMap(const DerivedNodeTree &tree, fn::MFNetwork &network)
: tree_(tree),
network_(network),
sockets_by_dsocket_id_(tree.sockets().size()),
socket_by_group_input_id_(tree.group_inputs().size(), nullptr)
: tree_(tree), network_(network)
{
}
@@ -76,96 +73,95 @@ class MFNetworkTreeMap {
void add(const DSocket &dsocket, fn::MFSocket &socket)
{
BLI_assert(dsocket.is_input() == socket.is_input());
BLI_assert(dsocket.is_input() || sockets_by_dsocket_id_[dsocket.id()].size() == 0);
sockets_by_dsocket_id_[dsocket.id()].append(&socket);
BLI_assert(dsocket->is_input() == socket.is_input());
BLI_assert(dsocket->is_input() || sockets_by_dsocket_.lookup(dsocket).is_empty());
sockets_by_dsocket_.add(dsocket, &socket);
}
void add(const DInputSocket &dsocket, fn::MFInputSocket &socket)
{
sockets_by_dsocket_id_[dsocket.id()].append(&socket);
sockets_by_dsocket_.add(dsocket, &socket);
}
void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket)
{
/* There can be at most one matching output socket. */
BLI_assert(sockets_by_dsocket_id_[dsocket.id()].size() == 0);
sockets_by_dsocket_id_[dsocket.id()].append(&socket);
BLI_assert(sockets_by_dsocket_.lookup(dsocket).is_empty());
sockets_by_dsocket_.add(dsocket, &socket);
}
void add(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets)
void add(const DTreeContext &context,
Span<const InputSocketRef *> dsockets,
Span<fn::MFInputSocket *> sockets)
{
assert_same_size(dsockets, sockets);
for (int i : dsockets.index_range()) {
this->add(*dsockets[i], *sockets[i]);
this->add(DInputSocket(&context, dsockets[i]), *sockets[i]);
}
}
void add(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets)
void add(const DTreeContext &context,
Span<const OutputSocketRef *> dsockets,
Span<fn::MFOutputSocket *> sockets)
{
assert_same_size(dsockets, sockets);
for (int i : dsockets.index_range()) {
this->add(*dsockets[i], *sockets[i]);
this->add(DOutputSocket(&context, dsockets[i]), *sockets[i]);
}
}
void add(const DGroupInput &group_input, fn::MFOutputSocket &socket)
{
BLI_assert(socket_by_group_input_id_[group_input.id()] == nullptr);
socket_by_group_input_id_[group_input.id()] = &socket;
}
void add_try_match(const DNode &dnode, fn::MFNode &node)
{
this->add_try_match(dnode.inputs().cast<const DSocket *>(),
this->add_try_match(*dnode.context(),
dnode->inputs().cast<const SocketRef *>(),
node.inputs().cast<fn::MFSocket *>());
this->add_try_match(dnode.outputs().cast<const DSocket *>(),
this->add_try_match(*dnode.context(),
dnode->outputs().cast<const SocketRef *>(),
node.outputs().cast<fn::MFSocket *>());
}
void add_try_match(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets)
void add_try_match(const DTreeContext &context,
Span<const InputSocketRef *> dsockets,
Span<fn::MFInputSocket *> sockets)
{
this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>());
this->add_try_match(
context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>());
}
void add_try_match(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets)
void add_try_match(const DTreeContext &context,
Span<const OutputSocketRef *> dsockets,
Span<fn::MFOutputSocket *> sockets)
{
this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>());
this->add_try_match(
context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>());
}
void add_try_match(Span<const DSocket *> dsockets, Span<fn::MFSocket *> sockets)
void add_try_match(const DTreeContext &context,
Span<const SocketRef *> dsockets,
Span<fn::MFSocket *> sockets)
{
int used_sockets = 0;
for (const DSocket *dsocket : dsockets) {
for (const SocketRef *dsocket : dsockets) {
if (!dsocket->is_available()) {
continue;
}
if (!socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
if (!socket_is_mf_data_socket(*dsocket->typeinfo())) {
continue;
}
fn::MFSocket *socket = sockets[used_sockets];
this->add(*dsocket, *socket);
this->add(DSocket(&context, dsocket), *socket);
used_sockets++;
}
}
fn::MFOutputSocket &lookup(const DGroupInput &group_input)
{
fn::MFOutputSocket *socket = socket_by_group_input_id_[group_input.id()];
BLI_assert(socket != nullptr);
return *socket;
}
fn::MFOutputSocket &lookup(const DOutputSocket &dsocket)
{
auto &sockets = sockets_by_dsocket_id_[dsocket.id()];
BLI_assert(sockets.size() == 1);
return sockets[0]->as_output();
return sockets_by_dsocket_.lookup(dsocket)[0]->as_output();
}
Span<fn::MFInputSocket *> lookup(const DInputSocket &dsocket)
{
return sockets_by_dsocket_id_[dsocket.id()].as_span().cast<fn::MFInputSocket *>();
return sockets_by_dsocket_.lookup(dsocket).cast<fn::MFInputSocket *>();
}
fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket)
@@ -186,7 +182,7 @@ class MFNetworkTreeMap {
bool is_mapped(const DSocket &dsocket) const
{
return sockets_by_dsocket_id_[dsocket.id()].size() >= 1;
return !sockets_by_dsocket_.lookup(dsocket).is_empty();
}
};
@@ -258,12 +254,7 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
public:
SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket)
: MFNetworkBuilderBase(common), bsocket_(dsocket.bsocket())
{
}
SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DGroupInput &group_input)
: MFNetworkBuilderBase(common), bsocket_(group_input.bsocket())
: MFNetworkBuilderBase(common), bsocket_(dsocket->bsocket())
{
}
@@ -331,11 +322,11 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
*/
class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
private:
const DNode &dnode_;
DNode node_;
public:
NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DNode &dnode)
: MFNetworkBuilderBase(common), dnode_(dnode)
NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, DNode node)
: MFNetworkBuilderBase(common), node_(node)
{
}
@@ -352,7 +343,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
const fn::MultiFunction &get_not_implemented_fn()
{
return this->get_default_fn("Not Implemented (" + dnode_.name() + ")");
return this->get_default_fn("Not Implemented (" + node_->name() + ")");
}
const fn::MultiFunction &get_default_fn(StringRef name);
@@ -369,7 +360,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
void set_matching_fn(const fn::MultiFunction &function)
{
fn::MFFunctionNode &node = common_.network.add_function(function);
common_.network_map.add_try_match(dnode_, node);
common_.network_map.add_try_match(node_, node);
}
/**
@@ -377,7 +368,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
*/
bNode &bnode()
{
return *dnode_.node_ref().bnode();
return *node_->bnode();
}
/**
@@ -385,7 +376,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
*/
const DNode &dnode() const
{
return dnode_;
return node_;
}
};
@@ -393,7 +384,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
const DerivedNodeTree &tree,
ResourceCollector &resources);
using MultiFunctionByNode = Map<const DNode *, const fn::MultiFunction *>;
using MultiFunctionByNode = Map<DNode, const fn::MultiFunction *>;
MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
ResourceCollector &resources);

View File

@@ -26,9 +26,9 @@ static void fn_node_group_instance_id_expand_in_mf_network(
{
const blender::nodes::DNode &node = builder.dnode();
std::string id = "/";
for (const blender::nodes::DParentNode *parent = node.parent(); parent;
parent = parent->parent()) {
id = "/" + parent->node_ref().name() + id;
for (const blender::nodes::DTreeContext *context = node.context(); context;
context = context->parent_context()) {
id = "/" + context->parent_node()->name() + id;
}
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<std::string>>(
std::move(id));

View File

@@ -67,12 +67,12 @@ static void fn_node_random_float_expand_in_mf_network(
blender::nodes::NodeMFNetworkBuilder &builder)
{
uint32_t function_seed = 1746872341u;
const blender::nodes::DNode &node = builder.dnode();
blender::nodes::DNode node = builder.dnode();
const blender::DefaultHash<blender::StringRefNull> hasher;
function_seed = 33 * function_seed + hasher(node.name());
for (const blender::nodes::DParentNode *parent = node.parent(); parent != nullptr;
parent = parent->parent()) {
function_seed = 33 * function_seed + hasher(parent->node_ref().name());
function_seed = 33 * function_seed + hasher(node->name());
for (const blender::nodes::DTreeContext *context = node.context(); context != nullptr;
context = context->parent_context()) {
function_seed = 33 * function_seed + hasher(context->parent_node()->name());
}
builder.construct_and_set_matching_fn<RandomFloatFunction>(function_seed);

View File

@@ -16,518 +16,217 @@
#include "NOD_derived_node_tree.hh"
#include "BLI_dot_export.hh"
#define UNINITIALIZED_ID UINT32_MAX
namespace blender::nodes {
DerivedNodeTree::DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs) : btree_(btree)
DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs)
{
BLI_assert(btree != nullptr);
const NodeTreeRef &main_tree_ref = get_tree_ref_from_map(node_tree_refs, *btree);
used_node_tree_refs_.add_new(&main_tree_ref);
Vector<DNode *> all_nodes;
Vector<DGroupInput *> all_group_inputs;
Vector<DParentNode *> all_parent_nodes;
this->insert_nodes_and_links_in_id_order(main_tree_ref, nullptr, all_nodes);
this->expand_groups(all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs);
this->relink_and_remove_muted_nodes(all_nodes);
this->remove_expanded_group_interfaces(all_nodes);
this->remove_unused_group_inputs(all_group_inputs);
this->store_in_this_and_init_ids(
std::move(all_nodes), std::move(all_group_inputs), std::move(all_parent_nodes));
root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs);
}
BLI_NOINLINE void DerivedNodeTree::insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref,
DParentNode *parent,
Vector<DNode *> &all_nodes)
DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context,
const NodeRef *parent_node,
bNodeTree &btree,
NodeTreeRefMap &node_tree_refs)
{
Array<DSocket *, 64> sockets_map(tree_ref.sockets().size());
DTreeContext &context = *allocator_.construct<DTreeContext>();
context.parent_context_ = parent_context;
context.parent_node_ = parent_node;
context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree);
used_node_tree_refs_.add(context.tree_);
/* Insert nodes. */
for (const NodeRef *node_ref : tree_ref.nodes()) {
DNode &node = this->create_node(*node_ref, parent, sockets_map);
all_nodes.append(&node);
}
/* Insert links. */
for (const NodeRef *node_ref : tree_ref.nodes()) {
for (const InputSocketRef *to_socket_ref : node_ref->inputs()) {
DInputSocket *to_socket = static_cast<DInputSocket *>(sockets_map[to_socket_ref->id()]);
for (const OutputSocketRef *from_socket_ref : to_socket_ref->linked_sockets()) {
DOutputSocket *from_socket = static_cast<DOutputSocket *>(
sockets_map[from_socket_ref->id()]);
to_socket->linked_sockets_.append(from_socket);
from_socket->linked_sockets_.append(to_socket);
}
}
}
}
DNode &DerivedNodeTree::create_node(const NodeRef &node_ref,
DParentNode *parent,
MutableSpan<DSocket *> r_sockets_map)
{
DNode &node = *allocator_.construct<DNode>();
node.node_ref_ = &node_ref;
node.parent_ = parent;
node.id_ = UNINITIALIZED_ID;
node.inputs_ = allocator_.construct_elements_and_pointer_array<DInputSocket>(
node_ref.inputs().size());
node.outputs_ = allocator_.construct_elements_and_pointer_array<DOutputSocket>(
node_ref.outputs().size());
for (int i : node.inputs_.index_range()) {
const InputSocketRef &socket_ref = node_ref.input(i);
DInputSocket &socket = *node.inputs_[i];
socket.is_multi_input_socket_ = socket_ref.bsocket()->flag & SOCK_MULTI_INPUT;
socket.id_ = UNINITIALIZED_ID;
socket.node_ = &node;
socket.socket_ref_ = &socket_ref;
r_sockets_map[socket_ref.id()] = &socket;
}
for (int i : node.outputs_.index_range()) {
const OutputSocketRef &socket_ref = node_ref.output(i);
DOutputSocket &socket = *node.outputs_[i];
socket.id_ = UNINITIALIZED_ID;
socket.node_ = &node;
socket.socket_ref_ = &socket_ref;
r_sockets_map[socket_ref.id()] = &socket;
}
return node;
}
BLI_NOINLINE void DerivedNodeTree::expand_groups(Vector<DNode *> &all_nodes,
Vector<DGroupInput *> &all_group_inputs,
Vector<DParentNode *> &all_parent_nodes,
NodeTreeRefMap &node_tree_refs)
{
for (int i = 0; i < all_nodes.size(); i++) {
DNode &node = *all_nodes[i];
if (node.node_ref_->is_group_node()) {
/* Muted nodes are relinked in a separate step. */
if (!node.node_ref_->is_muted()) {
this->expand_group_node(
node, all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs);
}
}
}
}
BLI_NOINLINE void DerivedNodeTree::expand_group_node(DNode &group_node,
Vector<DNode *> &all_nodes,
Vector<DGroupInput *> &all_group_inputs,
Vector<DParentNode *> &all_parent_nodes,
NodeTreeRefMap &node_tree_refs)
{
const NodeRef &group_node_ref = *group_node.node_ref_;
BLI_assert(group_node_ref.is_group_node());
bNodeTree *btree = reinterpret_cast<bNodeTree *>(group_node_ref.bnode()->id);
if (btree == nullptr) {
return;
}
const NodeTreeRef &group_ref = get_tree_ref_from_map(node_tree_refs, *btree);
used_node_tree_refs_.add(&group_ref);
DParentNode &parent = *allocator_.construct<DParentNode>();
parent.id_ = all_parent_nodes.append_and_get_index(&parent);
parent.parent_ = group_node.parent_;
parent.node_ref_ = &group_node_ref;
this->insert_nodes_and_links_in_id_order(group_ref, &parent, all_nodes);
Span<DNode *> new_nodes_by_id = all_nodes.as_span().take_back(group_ref.nodes().size());
this->create_group_inputs_for_unlinked_inputs(group_node, all_group_inputs);
this->relink_group_inputs(group_ref, new_nodes_by_id, group_node);
this->relink_group_outputs(group_ref, new_nodes_by_id, group_node);
}
BLI_NOINLINE void DerivedNodeTree::create_group_inputs_for_unlinked_inputs(
DNode &node, Vector<DGroupInput *> &all_group_inputs)
{
for (DInputSocket *input_socket : node.inputs_) {
if (input_socket->is_linked()) {
continue;
}
DGroupInput &group_input = *allocator_.construct<DGroupInput>();
group_input.id_ = UNINITIALIZED_ID;
group_input.socket_ref_ = &input_socket->socket_ref();
group_input.parent_ = node.parent_;
group_input.linked_sockets_.append(input_socket);
input_socket->linked_group_inputs_.append(&group_input);
all_group_inputs.append(&group_input);
}
}
BLI_NOINLINE void DerivedNodeTree::relink_group_inputs(const NodeTreeRef &group_ref,
Span<DNode *> nodes_by_id,
DNode &group_node)
{
Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupInput");
if (node_refs.size() == 0) {
return;
}
int input_amount = group_node.inputs().size();
for (int input_index : IndexRange(input_amount)) {
DInputSocket *outside_group = group_node.inputs_[input_index];
for (DOutputSocket *outside_connected : outside_group->linked_sockets_) {
outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group);
}
for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) {
outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group);
}
for (const NodeRef *input_node_ref : node_refs) {
DNode &input_node = *nodes_by_id[input_node_ref->id()];
DOutputSocket *inside_group = input_node.outputs_[input_index];
for (DInputSocket *inside_connected : inside_group->linked_sockets_) {
inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group);
for (DOutputSocket *outside_connected : outside_group->linked_sockets_) {
inside_connected->linked_sockets_.append(outside_connected);
outside_connected->linked_sockets_.append(inside_connected);
}
for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) {
inside_connected->linked_group_inputs_.append(outside_connected);
outside_connected->linked_sockets_.append(inside_connected);
}
}
inside_group->linked_sockets_.clear();
}
outside_group->linked_sockets_.clear();
outside_group->linked_group_inputs_.clear();
}
}
BLI_NOINLINE void DerivedNodeTree::relink_group_outputs(const NodeTreeRef &group_ref,
Span<DNode *> nodes_by_id,
DNode &group_node)
{
Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupOutput");
if (node_refs.size() == 0) {
return;
}
/* TODO: Pick correct group output node if there are more than one. */
const NodeRef &output_node_ref = *node_refs[0];
DNode &output_node = *nodes_by_id[output_node_ref.id()];
int output_amount = group_node.outputs().size();
BLI_assert(output_amount == output_node_ref.inputs().size() - 1);
for (int output_index : IndexRange(output_amount)) {
DOutputSocket *outside_group = group_node.outputs_[output_index];
DInputSocket *inside_group = output_node.inputs_[output_index];
for (DInputSocket *outside_connected : outside_group->linked_sockets_) {
outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group);
}
for (DOutputSocket *inside_connected : inside_group->linked_sockets_) {
inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group);
for (DInputSocket *outside_connected : outside_group->linked_sockets_) {
inside_connected->linked_sockets_.append(outside_connected);
outside_connected->linked_sockets_.append(inside_connected);
}
}
for (DGroupInput *inside_connected : inside_group->linked_group_inputs_) {
inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group);
for (DInputSocket *outside_connected : outside_group->linked_sockets_) {
inside_connected->linked_sockets_.append(outside_connected);
outside_connected->linked_group_inputs_.append(inside_connected);
}
}
outside_group->linked_sockets_.clear();
inside_group->linked_sockets_.clear();
}
}
BLI_NOINLINE void DerivedNodeTree::remove_expanded_group_interfaces(Vector<DNode *> &all_nodes)
{
int index = 0;
while (index < all_nodes.size()) {
DNode &node = *all_nodes[index];
const NodeRef &node_ref = *node.node_ref_;
if (node_ref.is_group_node() ||
(node.parent_ != nullptr &&
(node_ref.is_group_input_node() || node_ref.is_group_output_node()))) {
all_nodes.remove_and_reorder(index);
node.destruct_with_sockets();
}
else {
index++;
}
}
}
BLI_NOINLINE void DerivedNodeTree::remove_unused_group_inputs(
Vector<DGroupInput *> &all_group_inputs)
{
int index = 0;
while (index < all_group_inputs.size()) {
DGroupInput &group_input = *all_group_inputs[index];
if (group_input.linked_sockets_.is_empty()) {
all_group_inputs.remove_and_reorder(index);
group_input.~DGroupInput();
}
else {
index++;
}
}
}
BLI_NOINLINE void DerivedNodeTree::relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes)
{
int index = 0;
while (index < all_nodes.size()) {
DNode &node = *all_nodes[index];
const NodeRef &node_ref = *node.node_ref_;
if (node_ref.is_muted()) {
this->relink_muted_node(node);
all_nodes.remove_and_reorder(index);
node.destruct_with_sockets();
}
else {
index++;
}
}
}
BLI_NOINLINE void DerivedNodeTree::relink_muted_node(DNode &node)
{
const bNode &bnode = *node.bnode();
LISTBASE_FOREACH (const bNodeLink *, internal_link, &bnode.internal_links) {
BLI_assert(internal_link->fromnode == &bnode);
BLI_assert(internal_link->tonode == &bnode);
bNodeSocket *input_bsocket = internal_link->fromsock;
bNodeSocket *output_bsocket = internal_link->tosock;
/* Find internally linked sockets. */
DInputSocket *input_socket = nullptr;
DOutputSocket *output_socket = nullptr;
for (DInputSocket *socket : node.inputs_) {
if (socket->bsocket() == input_bsocket) {
input_socket = socket;
break;
}
}
for (DOutputSocket *socket : node.outputs_) {
if (socket->bsocket() == output_bsocket) {
output_socket = socket;
break;
}
}
BLI_assert(input_socket != nullptr);
BLI_assert(output_socket != nullptr);
/* Link sockets connected to the input to sockets that are connected to the internally linked
* output. */
for (DInputSocket *to_socket : output_socket->linked_sockets_) {
for (DOutputSocket *from_socket : input_socket->linked_sockets_) {
from_socket->linked_sockets_.append_non_duplicates(to_socket);
to_socket->linked_sockets_.append_non_duplicates(from_socket);
}
for (DGroupInput *group_input : input_socket->linked_group_inputs_) {
group_input->linked_sockets_.append_non_duplicates(to_socket);
to_socket->linked_group_inputs_.append_non_duplicates(group_input);
for (const NodeRef *node : context.tree_->nodes()) {
if (node->is_group_node()) {
bNode *bnode = node->bnode();
bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id);
if (child_btree != nullptr) {
DTreeContext &child = this->construct_context_recursively(
&context, node, *child_btree, node_tree_refs);
context.children_.add_new(node, &child);
}
}
}
/* Remove remaining links from muted node. */
for (DInputSocket *to_socket : node.inputs_) {
for (DOutputSocket *from_socket : to_socket->linked_sockets_) {
from_socket->linked_sockets_.remove_first_occurrence_and_reorder(to_socket);
}
for (DGroupInput *from_group_input : to_socket->linked_group_inputs_) {
from_group_input->linked_sockets_.remove_first_occurrence_and_reorder(to_socket);
}
to_socket->linked_sockets_.clear();
to_socket->linked_group_inputs_.clear();
}
for (DOutputSocket *from_socket : node.outputs_) {
for (DInputSocket *to_socket : from_socket->linked_sockets_) {
to_socket->linked_sockets_.remove_first_occurrence_and_reorder(from_socket);
}
from_socket->linked_sockets_.clear();
}
}
void DNode::destruct_with_sockets()
{
for (DInputSocket *socket : inputs_) {
socket->~DInputSocket();
}
for (DOutputSocket *socket : outputs_) {
socket->~DOutputSocket();
}
this->~DNode();
}
BLI_NOINLINE void DerivedNodeTree::store_in_this_and_init_ids(
Vector<DNode *> &&all_nodes,
Vector<DGroupInput *> &&all_group_inputs,
Vector<DParentNode *> &&all_parent_nodes)
{
nodes_by_id_ = std::move(all_nodes);
group_inputs_ = std::move(all_group_inputs);
parent_nodes_ = std::move(all_parent_nodes);
for (int node_index : nodes_by_id_.index_range()) {
DNode *node = nodes_by_id_[node_index];
node->id_ = node_index;
const bNodeType *nodetype = node->node_ref_->bnode()->typeinfo;
nodes_by_type_.add(nodetype, node);
for (DInputSocket *socket : node->inputs_) {
socket->id_ = sockets_by_id_.append_and_get_index(socket);
input_sockets_.append(socket);
}
for (DOutputSocket *socket : node->outputs_) {
socket->id_ = sockets_by_id_.append_and_get_index(socket);
output_sockets_.append(socket);
}
}
for (int i : group_inputs_.index_range()) {
group_inputs_[i]->id_ = i;
}
return context;
}
DerivedNodeTree::~DerivedNodeTree()
{
for (DInputSocket *socket : input_sockets_) {
socket->~DInputSocket();
}
for (DOutputSocket *socket : output_sockets_) {
socket->~DOutputSocket();
}
for (DNode *node : nodes_by_id_) {
node->~DNode();
}
for (DGroupInput *group_input : group_inputs_) {
group_input->~DGroupInput();
}
for (DParentNode *parent : parent_nodes_) {
parent->~DParentNode();
/* Has to be destructed manually, because the context info is allocated in a linear allocator. */
this->destruct_context_recursively(root_context_);
}
void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
{
for (DTreeContext *child : context->children_.values()) {
this->destruct_context_recursively(child);
}
context->~DTreeContext();
}
bool DerivedNodeTree::has_link_cycles() const
{
for (const NodeTreeRef *tree : used_node_tree_refs_) {
if (tree->has_link_cycles()) {
for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
if (tree_ref->has_link_cycles()) {
return true;
}
}
return false;
}
static dot::Cluster *get_cluster_for_parent(dot::DirectedGraph &graph,
Map<const DParentNode *, dot::Cluster *> &clusters,
const DParentNode *parent)
void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const
{
if (parent == nullptr) {
return nullptr;
}
return clusters.lookup_or_add_cb(parent, [&]() {
dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent());
bNodeTree *btree = reinterpret_cast<bNodeTree *>(parent->node_ref().bnode()->id);
dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " +
StringRef(btree->id.name + 2));
new_cluster->set_parent_cluster(parent_cluster);
return new_cluster;
});
this->foreach_node_in_context_recursive(*root_context_, callback);
}
std::string DerivedNodeTree::to_dot() const
void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context,
FunctionRef<void(DNode)> callback) const
{
dot::DirectedGraph digraph;
digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
Map<const DNode *, dot::NodeWithSocketsRef> dot_nodes;
Map<const DGroupInput *, dot::NodeWithSocketsRef> dot_group_inputs;
Map<const DParentNode *, dot::Cluster *> dot_clusters;
for (const DNode *node : nodes_by_id_) {
dot::Node &dot_node = digraph.new_node("");
dot_node.set_background_color("white");
Vector<std::string> input_names;
for (const DInputSocket *socket : node->inputs()) {
input_names.append(socket->name());
}
Vector<std::string> output_names;
for (const DOutputSocket *socket : node->outputs()) {
output_names.append(socket->name());
}
dot_nodes.add_new(node,
dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names));
dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent());
dot_node.set_parent_cluster(cluster);
for (const NodeRef *node_ref : context.tree_->nodes()) {
callback(DNode(&context, node_ref));
}
for (const DGroupInput *group_input : group_inputs_) {
dot::Node &dot_node = digraph.new_node("");
dot_node.set_background_color("white");
std::string group_input_name = group_input->name();
dot_group_inputs.add_new(
group_input, dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name}));
dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent());
dot_node.set_parent_cluster(cluster);
for (const DTreeContext *child_context : context.children_.values()) {
this->foreach_node_in_context_recursive(*child_context, callback);
}
}
for (const DNode *to_node : nodes_by_id_) {
dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node);
DOutputSocket DInputSocket::get_corresponding_group_node_output() const
{
BLI_assert(*this);
BLI_assert(socket_ref_->node().is_group_output_node());
BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1);
for (const DInputSocket *to_socket : to_node->inputs()) {
for (const DOutputSocket *from_socket : to_socket->linked_sockets()) {
const DNode *from_node = &from_socket->node();
dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node);
const DTreeContext *parent_context = context_->parent_context();
const NodeRef *parent_node = context_->parent_node();
BLI_assert(parent_context != nullptr);
BLI_assert(parent_node != nullptr);
digraph.new_edge(from_dot_node.output(from_socket->index()),
to_dot_node.input(to_socket->index()));
}
for (const DGroupInput *group_input : to_socket->linked_group_inputs()) {
dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input);
const int socket_index = socket_ref_->index();
return {parent_context, &parent_node->output(socket_index)};
}
digraph.new_edge(from_dot_node.output(0), to_dot_node.input(to_socket->index()));
DOutputSocket DInputSocket::get_corresponding_group_input_socket() const
{
BLI_assert(*this);
BLI_assert(socket_ref_->node().is_group_node());
const DTreeContext *child_context = context_->child_context(socket_ref_->node());
BLI_assert(child_context != nullptr);
const NodeTreeRef &child_tree = child_context->tree();
Span<const NodeRef *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput");
BLI_assert(!group_input_nodes.is_empty());
const int socket_index = socket_ref_->index();
return {child_context, &group_input_nodes[0]->output(socket_index)};
}
DInputSocket DOutputSocket::get_corresponding_group_node_input() const
{
BLI_assert(*this);
BLI_assert(socket_ref_->node().is_group_input_node());
BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1);
const DTreeContext *parent_context = context_->parent_context();
const NodeRef *parent_node = context_->parent_node();
BLI_assert(parent_context != nullptr);
BLI_assert(parent_node != nullptr);
const int socket_index = socket_ref_->index();
return {parent_context, &parent_node->input(socket_index)};
}
DInputSocket DOutputSocket::get_corresponding_group_output_socket() const
{
BLI_assert(*this);
BLI_assert(socket_ref_->node().is_group_node());
const DTreeContext *child_context = context_->child_context(socket_ref_->node());
BLI_assert(child_context != nullptr);
const NodeTreeRef &child_tree = child_context->tree();
Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput");
BLI_assert(!group_output_nodes.is_empty());
const int socket_index = socket_ref_->index();
return {child_context, &group_output_nodes[0]->input(socket_index)};
}
void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback) const
{
BLI_assert(*this);
for (const OutputSocketRef *linked_socket : socket_ref_->as_input().linked_sockets()) {
const NodeRef &linked_node = linked_socket->node();
DOutputSocket linked_dsocket{context_, linked_socket};
if (linked_node.is_muted()) {
for (const InternalLinkRef *internal_link : linked_node.internal_links()) {
if (&internal_link->to() == linked_socket) {
DInputSocket input_of_muted_node{context_, &internal_link->from()};
input_of_muted_node.foreach_origin_socket(callback);
}
}
}
else if (linked_node.is_group_input_node()) {
if (context_->is_root()) {
callback(linked_dsocket);
}
else {
DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input();
if (socket_in_parent_group->is_linked()) {
socket_in_parent_group.foreach_origin_socket(callback);
}
else {
callback(socket_in_parent_group);
}
}
}
else if (linked_node.is_group_node()) {
DInputSocket socket_in_group = linked_dsocket.get_corresponding_group_output_socket();
if (socket_in_group->is_linked()) {
socket_in_group.foreach_origin_socket(callback);
}
else {
callback(socket_in_group);
}
}
else {
callback(linked_dsocket);
}
}
}
digraph.set_random_cluster_bgcolors();
return digraph.to_dot_string();
void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const
{
for (const InputSocketRef *linked_socket : socket_ref_->as_output().linked_sockets()) {
const NodeRef &linked_node = linked_socket->node();
DInputSocket linked_dsocket{context_, linked_socket};
if (linked_node.is_muted()) {
for (const InternalLinkRef *internal_link : linked_node.internal_links()) {
if (&internal_link->from() == linked_socket) {
DOutputSocket output_of_muted_node{context_, &internal_link->to()};
output_of_muted_node.foreach_target_socket(callback);
}
}
}
else if (linked_node.is_group_output_node()) {
if (context_->is_root()) {
callback(linked_dsocket);
}
else {
DOutputSocket socket_in_parent_group =
linked_dsocket.get_corresponding_group_node_output();
socket_in_parent_group.foreach_target_socket(callback);
}
}
else if (linked_node.is_group_node()) {
DOutputSocket socket_in_group = linked_dsocket.get_corresponding_group_input_socket();
socket_in_group.foreach_target_socket(callback);
}
else {
callback(linked_dsocket);
}
}
}
} // namespace blender::nodes

View File

@@ -20,7 +20,6 @@
#include "DEG_depsgraph_query.h"
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_exec.hh"
#include "NOD_type_callbacks.hh"
@@ -30,7 +29,7 @@ namespace blender::nodes {
void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const
{
bNodeTree *btree_cow = node_.node_ref().tree().btree();
bNodeTree *btree_cow = node_->btree();
BLI_assert(btree_cow != nullptr);
if (btree_cow == nullptr) {
return;
@@ -40,12 +39,12 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin
const NodeTreeEvaluationContext context(*self_object_, *modifier_);
BKE_nodetree_error_message_add(
*btree_original, context, *node_.bnode(), type, std::move(message));
*btree_original, context, *node_->bnode(), type, std::move(message));
}
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
{
for (const DSocket *socket : node_.inputs()) {
for (const InputSocketRef *socket : node_->inputs()) {
if (socket->is_available() && socket->name() == name) {
return socket->bsocket();
}
@@ -176,7 +175,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier,
const CPPType *requested_type) const
{
bNodeSocket *found_socket = nullptr;
for (const DSocket *socket : node_.inputs()) {
for (const InputSocketRef *socket : node_->inputs()) {
if (socket->identifier() == identifier) {
found_socket = socket->bsocket();
break;
@@ -186,7 +185,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier,
if (found_socket == nullptr) {
std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n";
std::cout << "Possible identifiers are: ";
for (const DSocket *socket : node_.inputs()) {
for (const InputSocketRef *socket : node_->inputs()) {
if (socket->is_available()) {
std::cout << "'" << socket->identifier() << "', ";
}
@@ -218,7 +217,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier,
void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &value_type) const
{
bNodeSocket *found_socket = nullptr;
for (const DSocket *socket : node_.outputs()) {
for (const OutputSocketRef *socket : node_->outputs()) {
if (socket->identifier() == identifier) {
found_socket = socket->bsocket();
break;
@@ -228,7 +227,7 @@ void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &va
if (found_socket == nullptr) {
std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n";
std::cout << "Possible identifiers are: ";
for (const DSocket *socket : node_.outputs()) {
for (const OutputSocketRef *socket : node_->outputs()) {
if (socket->is_available()) {
std::cout << "'" << socket->identifier() << "', ";
}

View File

@@ -29,17 +29,17 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
Vector<fn::MFDataType, 10> input_types;
Vector<fn::MFDataType, 10> output_types;
for (const DInputSocket *dsocket : dnode_.inputs()) {
for (const InputSocketRef *dsocket : node_->inputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo());
if (data_type.has_value()) {
input_types.append(*data_type);
}
}
}
for (const DOutputSocket *dsocket : dnode_.outputs()) {
for (const OutputSocketRef *dsocket : node_->outputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo());
if (data_type.has_value()) {
output_types.append(*data_type);
}
@@ -57,9 +57,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
Vector<fn::MFDataType, stack_capacity> input_types;
Vector<StringRef, stack_capacity> input_names;
Vector<const DInputSocket *, stack_capacity> input_dsockets;
Vector<const InputSocketRef *, stack_capacity> input_dsockets;
for (const DInputSocket *dsocket : dnode.inputs()) {
for (const InputSocketRef *dsocket : dnode->inputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
@@ -72,9 +72,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
Vector<fn::MFDataType, stack_capacity> output_types;
Vector<StringRef, stack_capacity> output_names;
Vector<const DOutputSocket *, stack_capacity> output_dsockets;
Vector<const OutputSocketRef *, stack_capacity> output_dsockets;
for (const DOutputSocket *dsocket : dnode.outputs()) {
for (const OutputSocketRef *dsocket : dnode->outputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
@@ -86,20 +86,20 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
}
fn::MFDummyNode &dummy_node = common.network.add_dummy(
dnode.name(), input_types, output_types, input_names, output_names);
dnode->name(), input_types, output_types, input_names, output_names);
common.network_map.add(input_dsockets, dummy_node.inputs());
common.network_map.add(output_dsockets, dummy_node.outputs());
common.network_map.add(*dnode.context(), input_dsockets, dummy_node.inputs());
common.network_map.add(*dnode.context(), output_dsockets, dummy_node.outputs());
}
static bool has_data_sockets(const DNode &dnode)
{
for (const DInputSocket *socket : dnode.inputs()) {
for (const InputSocketRef *socket : dnode->inputs()) {
if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
}
for (const DOutputSocket *socket : dnode.outputs()) {
for (const OutputSocketRef *socket : dnode->outputs()) {
if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
@@ -107,70 +107,39 @@ static bool has_data_sockets(const DNode &dnode)
return false;
}
static void foreach_node_to_insert(CommonMFNetworkBuilderData &common,
FunctionRef<void(DNode)> callback)
{
common.tree.foreach_node([&](const DNode dnode) {
if (dnode->is_group_node()) {
return;
}
/* Don't insert non-root group input/output nodes, because they will be inlined. */
if (!dnode.context()->is_root()) {
if (dnode->is_group_input_node() || dnode->is_group_output_node()) {
return;
}
}
callback(dnode);
});
}
/**
* Expands all function nodes in the multi-function network. Nodes that don't have an expand
* function, but do have data sockets, will get corresponding dummy nodes.
*/
static void insert_nodes(CommonMFNetworkBuilderData &common)
{
for (const DNode *dnode : common.tree.nodes()) {
const bNodeType *node_type = dnode->node_ref().bnode()->typeinfo;
foreach_node_to_insert(common, [&](const DNode dnode) {
const bNodeType *node_type = dnode->typeinfo();
if (node_type->expand_in_mf_network != nullptr) {
NodeMFNetworkBuilder builder{common, *dnode};
NodeMFNetworkBuilder builder{common, dnode};
node_type->expand_in_mf_network(builder);
}
else if (has_data_sockets(*dnode)) {
insert_dummy_node(common, *dnode);
else if (has_data_sockets(dnode)) {
insert_dummy_node(common, dnode);
}
}
}
static void insert_group_inputs(CommonMFNetworkBuilderData &common)
{
for (const DGroupInput *group_input : common.tree.group_inputs()) {
bNodeSocket *bsocket = group_input->bsocket();
if (socket_is_mf_data_socket(*bsocket->typeinfo)) {
bNodeSocketType *socktype = bsocket->typeinfo;
BLI_assert(socktype->expand_in_mf_network != nullptr);
SocketMFNetworkBuilder builder{common, *group_input};
socktype->expand_in_mf_network(builder);
fn::MFOutputSocket *from_socket = builder.built_socket();
BLI_assert(from_socket != nullptr);
common.network_map.add(*group_input, *from_socket);
}
}
}
static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common,
const DInputSocket &to_dsocket)
{
Span<const DOutputSocket *> from_dsockets = to_dsocket.linked_sockets();
Span<const DGroupInput *> from_group_inputs = to_dsocket.linked_group_inputs();
int total_linked_amount = from_dsockets.size() + from_group_inputs.size();
BLI_assert(total_linked_amount <= 1);
if (total_linked_amount == 0) {
return nullptr;
}
if (from_dsockets.size() == 1) {
const DOutputSocket &from_dsocket = *from_dsockets[0];
if (!from_dsocket.is_available()) {
return nullptr;
}
if (socket_is_mf_data_socket(*from_dsocket.bsocket()->typeinfo)) {
return &common.network_map.lookup(from_dsocket);
}
return nullptr;
}
const DGroupInput &from_group_input = *from_group_inputs[0];
if (socket_is_mf_data_socket(*from_group_input.bsocket()->typeinfo)) {
return &common.network_map.lookup(from_group_input);
}
return nullptr;
});
}
template<typename From, typename To>
@@ -286,78 +255,84 @@ static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderD
return node.output(0);
}
static void insert_links(CommonMFNetworkBuilderData &common)
static fn::MFOutputSocket *insert_unlinked_input(CommonMFNetworkBuilderData &common,
const DInputSocket &dsocket)
{
for (const DInputSocket *to_dsocket : common.tree.input_sockets()) {
if (!to_dsocket->is_available()) {
continue;
}
if (!to_dsocket->is_linked()) {
continue;
}
if (!socket_is_mf_data_socket(*to_dsocket->bsocket()->typeinfo)) {
continue;
}
Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(*to_dsocket);
BLI_assert(to_sockets.size() >= 1);
fn::MFDataType to_type = to_sockets[0]->data_type();
fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket);
if (from_socket == nullptr) {
from_socket = &insert_default_value_for_type(common, to_type);
}
fn::MFDataType from_type = from_socket->data_type();
if (from_type != to_type) {
const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion(
from_type, to_type);
if (conversion_fn != nullptr) {
fn::MFNode &node = common.network.add_function(*conversion_fn);
common.network.add_link(*from_socket, node.input(0));
from_socket = &node.output(0);
}
else {
from_socket = &insert_default_value_for_type(common, to_type);
}
}
for (fn::MFInputSocket *to_socket : to_sockets) {
common.network.add_link(*from_socket, *to_socket);
}
}
}
static void insert_unlinked_input(CommonMFNetworkBuilderData &common, const DInputSocket &dsocket)
{
bNodeSocket *bsocket = dsocket.bsocket();
bNodeSocket *bsocket = dsocket->bsocket();
bNodeSocketType *socktype = bsocket->typeinfo;
BLI_assert(socktype->expand_in_mf_network != nullptr);
BLI_assert(socket_is_mf_data_socket(*socktype));
SocketMFNetworkBuilder builder{common, dsocket};
socktype->expand_in_mf_network(builder);
socket_expand_in_mf_network(builder);
fn::MFOutputSocket *from_socket = builder.built_socket();
BLI_assert(from_socket != nullptr);
for (fn::MFInputSocket *to_socket : common.network_map.lookup(dsocket)) {
common.network.add_link(*from_socket, *to_socket);
}
fn::MFOutputSocket *built_socket = builder.built_socket();
BLI_assert(built_socket != nullptr);
return built_socket;
}
static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common)
static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common)
{
Vector<const DInputSocket *> unlinked_data_inputs;
for (const DInputSocket *dsocket : common.tree.input_sockets()) {
if (dsocket->is_available()) {
if (socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
if (!dsocket->is_linked()) {
insert_unlinked_input(common, *dsocket);
foreach_node_to_insert(common, [&](const DNode dnode) {
for (const InputSocketRef *socket_ref : dnode->inputs()) {
const DInputSocket to_dsocket{dnode.context(), socket_ref};
if (!to_dsocket->is_available()) {
continue;
}
if (!socket_is_mf_data_socket(*to_dsocket->typeinfo())) {
continue;
}
Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(to_dsocket);
BLI_assert(to_sockets.size() >= 1);
const fn::MFDataType to_type = to_sockets[0]->data_type();
Vector<DSocket> from_dsockets;
to_dsocket.foreach_origin_socket([&](DSocket socket) { from_dsockets.append(socket); });
if (from_dsockets.size() > 1) {
fn::MFOutputSocket &from_socket = insert_default_value_for_type(common, to_type);
for (fn::MFInputSocket *to_socket : to_sockets) {
common.network.add_link(from_socket, *to_socket);
}
continue;
}
if (from_dsockets.is_empty()) {
/* The socket is not linked. Need to use the value of the socket itself. */
fn::MFOutputSocket *built_socket = insert_unlinked_input(common, to_dsocket);
for (fn::MFInputSocket *to_socket : to_sockets) {
common.network.add_link(*built_socket, *to_socket);
}
continue;
}
if (from_dsockets[0]->is_input()) {
DInputSocket from_dsocket{from_dsockets[0]};
fn::MFOutputSocket *built_socket = insert_unlinked_input(common, from_dsocket);
for (fn::MFInputSocket *to_socket : to_sockets) {
common.network.add_link(*built_socket, *to_socket);
}
continue;
}
DOutputSocket from_dsocket{from_dsockets[0]};
fn::MFOutputSocket *from_socket = &common.network_map.lookup(from_dsocket);
const fn::MFDataType from_type = from_socket->data_type();
if (from_type != to_type) {
const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion(
from_type, to_type);
if (conversion_fn != nullptr) {
fn::MFNode &node = common.network.add_function(*conversion_fn);
common.network.add_link(*from_socket, node.input(0));
from_socket = &node.output(0);
}
else {
from_socket = &insert_default_value_for_type(common, to_type);
}
}
for (fn::MFInputSocket *to_socket : to_sockets) {
common.network.add_link(*from_socket, *to_socket);
}
}
}
});
}
/**
@@ -376,9 +351,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
CommonMFNetworkBuilderData common{resources, network, network_map, tree};
insert_nodes(common);
insert_group_inputs(common);
insert_links(common);
insert_unlinked_inputs(common);
insert_links_and_unlinked_inputs(common);
return network_map;
}
@@ -420,16 +393,17 @@ static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map,
}
};
for (const DInputSocket *dsocket : dnode.inputs()) {
for (const InputSocketRef *dsocket : dnode->inputs()) {
if (dsocket->is_available()) {
for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
for (fn::MFInputSocket *mf_input :
network_map.lookup(DInputSocket(dnode.context(), dsocket))) {
check_mf_node(mf_input->node());
}
}
}
for (const DOutputSocket *dsocket : dnode.outputs()) {
for (const OutputSocketRef *dsocket : dnode->outputs()) {
if (dsocket->is_available()) {
fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket));
check_mf_node(mf_output.node());
}
}
@@ -451,20 +425,21 @@ static const fn::MultiFunction &create_function_for_node_that_expands_into_multi
ResourceCollector &resources)
{
Vector<const fn::MFOutputSocket *> dummy_fn_inputs;
for (const DInputSocket *dsocket : dnode.inputs()) {
for (const InputSocketRef *dsocket : dnode->inputs()) {
if (dsocket->is_available()) {
MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo());
fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type);
for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
for (fn::MFInputSocket *mf_input :
network_map.lookup(DInputSocket(dnode.context(), dsocket))) {
network.add_link(fn_input, *mf_input);
dummy_fn_inputs.append(&fn_input);
}
}
}
Vector<const fn::MFInputSocket *> dummy_fn_outputs;
for (const DOutputSocket *dsocket : dnode.outputs()) {
for (const OutputSocketRef *dsocket : dnode->outputs()) {
if (dsocket->is_available()) {
fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket));
MFDataType data_type = mf_output.data_type();
fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type);
network.add_link(mf_output, fn_output);
@@ -492,18 +467,18 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
CommonMFNetworkBuilderData common{resources, network, network_map, tree};
for (const DNode *dnode : tree.nodes()) {
tree.foreach_node([&](DNode dnode) {
const bNodeType *node_type = dnode->typeinfo();
if (node_type->expand_in_mf_network == nullptr) {
/* This node does not have a multi-function implementation. */
continue;
return;
}
NodeMFNetworkBuilder builder{common, *dnode};
NodeMFNetworkBuilder builder{common, dnode};
node_type->expand_in_mf_network(builder);
const fn::MultiFunction *single_function = nullptr;
const NodeExpandType expand_type = get_node_expand_type(network_map, *dnode, &single_function);
const NodeExpandType expand_type = get_node_expand_type(network_map, dnode, &single_function);
switch (expand_type) {
case NodeExpandType::HasDummyNodes: {
@@ -519,12 +494,12 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
/* If a node expanded into multiple functions, a new function has to be created that
* combines those. */
const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple(
*dnode, network, network_map, resources);
dnode, network, network_map, resources);
functions_by_node.add_new(dnode, &fn);
break;
}
}
}
});
return functions_by_node;
}

View File

@@ -116,7 +116,7 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild
blender::fn::MFNetwork &network = builder.network();
blender::fn::MFFunctionNode &base_node = network.add_function(base_function);
builder.network_map().add_try_match(dnode.inputs(), base_node.inputs());
builder.network_map().add_try_match(*dnode.context(), dnode->inputs(), base_node.inputs());
const bool clamp_output = builder.bnode().custom2 != 0;
if (clamp_output) {
@@ -126,10 +126,12 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild
}};
blender::fn::MFFunctionNode &clamp_node = network.add_function(clamp_fn);
network.add_link(base_node.output(0), clamp_node.input(0));
builder.network_map().add(dnode.output(0), clamp_node.output(0));
builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)),
clamp_node.output(0));
}
else {
builder.network_map().add(dnode.output(0), base_node.output(0));
builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)),
base_node.output(0));
}
}

View File

@@ -41,7 +41,7 @@ static int gpu_shader_value(GPUMaterial *mat,
static void sh_node_value_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
{
const bNodeSocket *bsocket = builder.dnode().output(0).bsocket();
const bNodeSocket *bsocket = builder.dnode()->output(0).bsocket();
const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value;
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
}