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

292 lines
9.3 KiB
C++
Raw Normal View History

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BKE_node_tree_multi_function.hh"
#include "BLI_float3.hh"
namespace blender {
namespace bke {
/* Maybe this should be moved to BKE_node.h. */
static std::optional<fn::MFDataType> try_get_multi_function_data_type_of_socket(
const bNodeSocket *bsocket)
{
if (bsocket->typeinfo->get_mf_data_type == nullptr) {
return {};
}
return bsocket->typeinfo->get_mf_data_type();
}
static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &dnode)
{
constexpr uint stack_capacity = 10;
Vector<fn::MFDataType, stack_capacity> input_types;
Vector<StringRef, stack_capacity> input_names;
Vector<const DInputSocket *, stack_capacity> input_dsockets;
for (const DInputSocket *dsocket : dnode.inputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
dsocket->bsocket());
if (data_type.has_value()) {
input_types.append(*data_type);
input_names.append(dsocket->name());
input_dsockets.append(dsocket);
}
}
}
Vector<fn::MFDataType, stack_capacity> output_types;
Vector<StringRef, stack_capacity> output_names;
Vector<const DOutputSocket *, stack_capacity> output_dsockets;
for (const DOutputSocket *dsocket : dnode.outputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
dsocket->bsocket());
if (data_type.has_value()) {
output_types.append(*data_type);
output_names.append(dsocket->name());
output_dsockets.append(dsocket);
}
}
}
fn::MFDummyNode &dummy_node = common.network.add_dummy(
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());
}
static bool has_data_sockets(const DNode &dnode)
{
for (const DInputSocket *socket : dnode.inputs()) {
if (is_multi_function_data_socket(socket->bsocket())) {
return true;
}
}
for (const DOutputSocket *socket : dnode.outputs()) {
if (is_multi_function_data_socket(socket->bsocket())) {
return true;
}
}
return false;
}
/**
* 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;
if (node_type->expand_in_mf_network != nullptr) {
NodeMFNetworkBuilder builder{common, *dnode};
node_type->expand_in_mf_network(builder);
}
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 (is_multi_function_data_socket(bsocket)) {
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();
uint 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) {
if (is_multi_function_data_socket(from_dsockets[0]->bsocket())) {
return &common.network_map.lookup(*from_dsockets[0]);
}
else {
return nullptr;
}
}
else {
if (is_multi_function_data_socket(from_group_inputs[0]->bsocket())) {
return &common.network_map.lookup(*from_group_inputs[0]);
}
else {
return nullptr;
}
}
}
static const fn::MultiFunction *try_get_conversion_function(fn::MFDataType from, fn::MFDataType to)
{
if (from == fn::MFDataType::ForSingle<float>()) {
if (to == fn::MFDataType::ForSingle<float3>()) {
static fn::CustomMF_Convert<float, float3> function;
return &function;
}
}
if (from == fn::MFDataType::ForSingle<float3>()) {
if (to == fn::MFDataType::ForSingle<float>()) {
static fn::CustomMF_SI_SO<float3, float> function{"Vector Length",
[](float3 a) { return a.length(); }};
return &function;
}
}
return nullptr;
}
static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderData &common,
fn::MFDataType type)
{
const fn::MultiFunction *default_fn;
if (type.is_single()) {
default_fn = &common.resources.construct<fn::CustomMF_GenericConstant>(
AT, type.single_type(), type.single_type().default_value());
}
else {
default_fn = &common.resources.construct<fn::CustomMF_GenericConstantArray>(
AT, fn::GSpan(type.vector_base_type()));
}
fn::MFNode &node = common.network.add_function(*default_fn);
return node.output(0);
}
static void insert_links(CommonMFNetworkBuilderData &common)
{
for (const DInputSocket *to_dsocket : common.tree.input_sockets()) {
if (!to_dsocket->is_available()) {
continue;
}
if (!to_dsocket->is_linked()) {
continue;
}
if (!is_multi_function_data_socket(to_dsocket->bsocket())) {
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 = try_get_conversion_function(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);
continue;
}
}
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();
bNodeSocketType *socktype = bsocket->typeinfo;
BLI_assert(socktype->expand_in_mf_network != nullptr);
SocketMFNetworkBuilder builder{common, dsocket};
socktype->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);
}
}
static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common)
{
Vector<const DInputSocket *> unlinked_data_inputs;
for (const DInputSocket *dsocket : common.tree.input_sockets()) {
if (dsocket->is_available()) {
if (is_multi_function_data_socket(dsocket->bsocket())) {
if (!dsocket->is_linked()) {
insert_unlinked_input(common, *dsocket);
}
}
}
}
}
/**
* Expands all function nodes contained in the given node tree within the given multi-function
* network.
*
* Returns a mapping between the original node tree and the generated nodes/sockets for further
* processing.
*/
MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
const DerivedNodeTree &tree,
ResourceCollector &resources)
{
MFNetworkTreeMap network_map{tree, network};
CommonMFNetworkBuilderData common{resources, network, network_map, tree};
insert_nodes(common);
insert_group_inputs(common);
insert_links(common);
insert_unlinked_inputs(common);
return network_map;
}
} // namespace bke
} // namespace blender