Nodes: support implicit conversions and incorrectly linked sockets
This commit is contained in:
parent
06401157a6
commit
c7eada103c
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "BKE_node_tree_multi_function.hh"
|
||||
|
||||
#include "BLI_float3.hh"
|
||||
|
||||
namespace blender {
|
||||
namespace bke {
|
||||
|
||||
|
@ -136,37 +138,93 @@ static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common,
|
|||
}
|
||||
|
||||
if (from_dsockets.size() == 1) {
|
||||
return &common.network_map.lookup(*from_dsockets[0]);
|
||||
if (is_multi_function_data_socket(from_dsockets[0]->bsocket())) {
|
||||
return &common.network_map.lookup(*from_dsockets[0]);
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return &common.network_map.lookup(*from_group_inputs[0]);
|
||||
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 (!is_multi_function_data_socket(to_dsocket->bsocket())) {
|
||||
if (!to_dsocket->is_linked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket);
|
||||
if (from_socket == nullptr) {
|
||||
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 from_type = from_socket->data_type();
|
||||
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) {
|
||||
/* Todo: Try inserting implicit conversion. */
|
||||
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) {
|
||||
|
|
|
@ -202,6 +202,30 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a multi-function that converts between two types.
|
||||
*/
|
||||
template<typename From, typename To> class CustomMF_Convert : public MultiFunction {
|
||||
public:
|
||||
CustomMF_Convert()
|
||||
{
|
||||
std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name();
|
||||
MFSignatureBuilder signature = this->get_builder(std::move(name));
|
||||
signature.single_input<From>("Input");
|
||||
signature.single_output<To>("Output");
|
||||
}
|
||||
|
||||
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
|
||||
{
|
||||
VSpan<From> inputs = params.readonly_single_input<From>(0);
|
||||
MutableSpan<To> outputs = params.uninitialized_single_output<To>(1);
|
||||
|
||||
for (uint i : mask) {
|
||||
new ((void *)&outputs[i]) To(inputs[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A multi-function that outputs the same value every time. The value is not owned by an instance
|
||||
* of this function. The caller is responsible for destructing and freeing the value.
|
||||
|
|
|
@ -364,4 +364,23 @@ TEST(multi_function, CustomMF_GenericConstantArray)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(multi_function, CustomMF_Convert)
|
||||
{
|
||||
CustomMF_Convert<float, int> fn;
|
||||
|
||||
Array<float> inputs = {5.4f, 7.1f, 9.0f};
|
||||
Array<int> outputs{inputs.size(), 0};
|
||||
|
||||
MFParamsBuilder params(fn, inputs.size());
|
||||
params.add_readonly_single_input(inputs.as_span());
|
||||
params.add_uninitialized_single_output(outputs.as_mutable_span());
|
||||
|
||||
MFContextBuilder context;
|
||||
fn.call({0, 2}, params, context);
|
||||
|
||||
EXPECT_EQ(outputs[0], 5);
|
||||
EXPECT_EQ(outputs[1], 0);
|
||||
EXPECT_EQ(outputs[2], 9);
|
||||
}
|
||||
|
||||
} // namespace blender::fn
|
||||
|
|
Loading…
Reference in New Issue