Functions: refactor multi-function builder API
* New `build_mf` namespace for the multi-function builders. * The type name of the created multi-functions is now "private", i.e. the caller has to use `auto`. This has the benefit that the implementation can change more freely without affecting the caller. * `CustomMF` does not use `std::function` internally anymore. This reduces some overhead during code generation and at run-time. * `CustomMF` now supports single-mutable parameters.
This commit is contained in:
parent
380db3edb3
commit
b3146200a8
|
@ -440,12 +440,12 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
make_array_write_attribute<float3>,
|
||||
tag_component_positions_changed);
|
||||
|
||||
static const fn::CustomMF_SI_SO<int8_t, int8_t> handle_type_clamp{
|
||||
static auto handle_type_clamp = fn::build_mf::SI1_SO<int8_t, int8_t>(
|
||||
"Handle Type Validate",
|
||||
[](int8_t value) {
|
||||
return std::clamp<int8_t>(value, BEZIER_HANDLE_FREE, BEZIER_HANDLE_ALIGN);
|
||||
},
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
static BuiltinCustomDataLayerProvider handle_type_right("handle_type_right",
|
||||
ATTR_DOMAIN_POINT,
|
||||
CD_PROP_INT8,
|
||||
|
@ -484,10 +484,10 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
make_array_write_attribute<float>,
|
||||
tag_component_positions_changed);
|
||||
|
||||
static const fn::CustomMF_SI_SO<int8_t, int8_t> nurbs_order_clamp{
|
||||
static const auto nurbs_order_clamp = fn::build_mf::SI1_SO<int8_t, int8_t>(
|
||||
"NURBS Order Validate",
|
||||
[](int8_t value) { return std::max<int8_t>(value, 0); },
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
static BuiltinCustomDataLayerProvider nurbs_order("nurbs_order",
|
||||
ATTR_DOMAIN_CURVE,
|
||||
CD_PROP_INT8,
|
||||
|
@ -501,12 +501,12 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
tag_component_topology_changed,
|
||||
AttributeValidator{&nurbs_order_clamp});
|
||||
|
||||
static const fn::CustomMF_SI_SO<int8_t, int8_t> normal_mode_clamp{
|
||||
static const auto normal_mode_clamp = fn::build_mf::SI1_SO<int8_t, int8_t>(
|
||||
"Normal Mode Validate",
|
||||
[](int8_t value) {
|
||||
return std::clamp<int8_t>(value, NORMAL_MODE_MINIMUM_TWIST, NORMAL_MODE_Z_UP);
|
||||
},
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
static BuiltinCustomDataLayerProvider normal_mode("normal_mode",
|
||||
ATTR_DOMAIN_CURVE,
|
||||
CD_PROP_INT8,
|
||||
|
@ -520,12 +520,12 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
tag_component_normals_changed,
|
||||
AttributeValidator{&normal_mode_clamp});
|
||||
|
||||
static const fn::CustomMF_SI_SO<int8_t, int8_t> knots_mode_clamp{
|
||||
static const auto knots_mode_clamp = fn::build_mf::SI1_SO<int8_t, int8_t>(
|
||||
"Knots Mode Validate",
|
||||
[](int8_t value) {
|
||||
return std::clamp<int8_t>(value, NURBS_KNOT_MODE_NORMAL, NURBS_KNOT_MODE_ENDPOINT_BEZIER);
|
||||
},
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode",
|
||||
ATTR_DOMAIN_CURVE,
|
||||
CD_PROP_INT8,
|
||||
|
@ -539,12 +539,12 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
tag_component_topology_changed,
|
||||
AttributeValidator{&knots_mode_clamp});
|
||||
|
||||
static const fn::CustomMF_SI_SO<int8_t, int8_t> curve_type_clamp{
|
||||
static const auto curve_type_clamp = fn::build_mf::SI1_SO<int8_t, int8_t>(
|
||||
"Curve Type Validate",
|
||||
[](int8_t value) {
|
||||
return std::clamp<int8_t>(value, CURVE_TYPE_CATMULL_ROM, CURVE_TYPES_NUM);
|
||||
},
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
static BuiltinCustomDataLayerProvider curve_type("curve_type",
|
||||
ATTR_DOMAIN_CURVE,
|
||||
CD_PROP_INT8,
|
||||
|
@ -558,10 +558,10 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
tag_component_curve_types_changed,
|
||||
AttributeValidator{&curve_type_clamp});
|
||||
|
||||
static const fn::CustomMF_SI_SO<int, int> resolution_clamp{
|
||||
static const auto resolution_clamp = fn::build_mf::SI1_SO<int, int>(
|
||||
"Resolution Validate",
|
||||
[](int value) { return std::max<int>(value, 1); },
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
static BuiltinCustomDataLayerProvider resolution("resolution",
|
||||
ATTR_DOMAIN_CURVE,
|
||||
CD_PROP_INT32,
|
||||
|
|
|
@ -1264,13 +1264,13 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
|||
make_array_write_attribute<int>,
|
||||
nullptr);
|
||||
|
||||
static const fn::CustomMF_SI_SO<int, int> material_index_clamp{
|
||||
static const auto material_index_clamp = fn::build_mf::SI1_SO<int, int>(
|
||||
"Material Index Validate",
|
||||
[](int value) {
|
||||
/* Use #short for the maximum since many areas still use that type for indices. */
|
||||
return std::clamp<int>(value, 0, std::numeric_limits<short>::max());
|
||||
},
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
static BuiltinCustomDataLayerProvider material_index("material_index",
|
||||
ATTR_DOMAIN_FACE,
|
||||
CD_PROP_INT32,
|
||||
|
|
|
@ -20,12 +20,12 @@ static void add_implicit_conversion(DataTypeConversions &conversions)
|
|||
static const CPPType &to_type = CPPType::get<To>();
|
||||
static const std::string conversion_name = from_type.name() + " to " + to_type.name();
|
||||
|
||||
static fn::CustomMF_SI_SO<From, To> multi_function{
|
||||
static auto multi_function = fn::build_mf::SI1_SO<From, To>(
|
||||
conversion_name.c_str(),
|
||||
/* Use lambda instead of passing #ConversionF directly, because otherwise the compiler won't
|
||||
* inline the function. */
|
||||
[](const From &a) { return ConversionF(a); },
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
static auto convert_single_to_initialized = [](const void *src, void *dst) {
|
||||
*(To *)dst = ConversionF(*(const From *)src);
|
||||
};
|
||||
|
|
|
@ -8,17 +8,15 @@
|
|||
* This file contains several utilities to create multi-functions with less redundant code.
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "FN_multi_function.hh"
|
||||
|
||||
namespace blender::fn {
|
||||
namespace blender::fn::build_mf {
|
||||
|
||||
/**
|
||||
* These presets determine what code is generated for a #CustomMF. Different presets make different
|
||||
* trade-offs between run-time performance and compile-time/binary size.
|
||||
*/
|
||||
namespace CustomMF_presets {
|
||||
namespace exec_presets {
|
||||
|
||||
/** Method to execute a function in case devirtualization was not possible. */
|
||||
enum class FallbackMode {
|
||||
|
@ -63,7 +61,7 @@ struct AllSpanOrSingle {
|
|||
auto create_devirtualizers(TypeSequence<ParamTags...> /*param_tags*/,
|
||||
std::index_sequence<I...> /*indices*/,
|
||||
const IndexMask &mask,
|
||||
const std::tuple<LoadedParams...> &loaded_params)
|
||||
const std::tuple<LoadedParams...> &loaded_params) const
|
||||
{
|
||||
return std::make_tuple(IndexMaskDevirtualizer<true, true>{mask}, [&]() {
|
||||
typedef ParamTags ParamTag;
|
||||
|
@ -72,7 +70,9 @@ struct AllSpanOrSingle {
|
|||
const GVArrayImpl &varray_impl = *std::get<I>(loaded_params);
|
||||
return GVArrayDevirtualizer<T, true, true>{varray_impl};
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleOutput) {
|
||||
else if constexpr (ELEM(ParamTag::category,
|
||||
MFParamCategory::SingleOutput,
|
||||
MFParamCategory::SingleMutable)) {
|
||||
T *ptr = std::get<I>(loaded_params);
|
||||
return BasicDevirtualizer<T *>{ptr};
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ template<size_t... Indices> struct SomeSpanOrSingle {
|
|||
auto create_devirtualizers(TypeSequence<ParamTags...> /*param_tags*/,
|
||||
std::index_sequence<I...> /*indices*/,
|
||||
const IndexMask &mask,
|
||||
const std::tuple<LoadedParams...> &loaded_params)
|
||||
const std::tuple<LoadedParams...> &loaded_params) const
|
||||
{
|
||||
return std::make_tuple(IndexMaskDevirtualizer<true, true>{mask}, [&]() {
|
||||
typedef ParamTags ParamTag;
|
||||
|
@ -104,7 +104,9 @@ template<size_t... Indices> struct SomeSpanOrSingle {
|
|||
const GVArrayImpl &varray_impl = *std::get<I>(loaded_params);
|
||||
return GVArrayDevirtualizer<T, true, UseSpan>{varray_impl};
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleOutput) {
|
||||
else if constexpr (ELEM(ParamTag::category,
|
||||
MFParamCategory::SingleOutput,
|
||||
MFParamCategory::SingleMutable)) {
|
||||
T *ptr = std::get<I>(loaded_params);
|
||||
return BasicDevirtualizer<T *>{ptr};
|
||||
}
|
||||
|
@ -112,7 +114,7 @@ template<size_t... Indices> struct SomeSpanOrSingle {
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace CustomMF_presets
|
||||
} // namespace exec_presets
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
@ -142,23 +144,23 @@ void execute_array(TypeSequence<ParamTags...> /*param_tags*/,
|
|||
* reference, because the pointer points to uninitialized memory. */
|
||||
return args + i;
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleMutable) {
|
||||
/* For mutables, pass a mutable reference to the function. */
|
||||
return args[i];
|
||||
}
|
||||
}()...);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace materialize_detail {
|
||||
|
||||
enum class ArgMode {
|
||||
enum class MaterializeArgMode {
|
||||
Unknown,
|
||||
Single,
|
||||
Span,
|
||||
Materialized,
|
||||
};
|
||||
|
||||
template<typename ParamTag> struct ArgInfo {
|
||||
ArgMode mode = ArgMode::Unknown;
|
||||
template<typename ParamTag> struct MaterializeArgInfo {
|
||||
MaterializeArgMode mode = MaterializeArgMode::Unknown;
|
||||
Span<typename ParamTag::base_type> internal_span;
|
||||
};
|
||||
|
||||
|
@ -182,9 +184,11 @@ void execute_materialized_impl(TypeSequence<ParamTags...> /*param_tags*/,
|
|||
return chunks[in_i];
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleOutput) {
|
||||
/* For outputs, a pointer is passed, because the memory is uninitialized. */
|
||||
return chunks + out_i;
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleMutable) {
|
||||
return chunks[out_i];
|
||||
}
|
||||
}()...);
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +221,7 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
|
|||
std::tuple<MutableSpan<typename ParamTags::base_type>...> buffers;
|
||||
|
||||
/* Information about every parameter. */
|
||||
std::tuple<ArgInfo<ParamTags>...> args_info;
|
||||
std::tuple<MaterializeArgInfo<ParamTags>...> args_info;
|
||||
|
||||
(
|
||||
/* Setup information for all parameters. */
|
||||
|
@ -225,7 +229,7 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
|
|||
/* Use `typedef` instead of `using` to work around a compiler bug. */
|
||||
typedef ParamTags ParamTag;
|
||||
typedef typename ParamTag::base_type T;
|
||||
[[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
|
||||
[[maybe_unused]] MaterializeArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
|
||||
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
|
||||
const GVArrayImpl &varray_impl = *std::get<I>(loaded_params);
|
||||
const CommonVArrayInfo common_info = varray_impl.common_info();
|
||||
|
@ -236,7 +240,7 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
|
|||
const T &in_single = *static_cast<const T *>(common_info.data);
|
||||
uninitialized_fill_n(in_chunk.data(), in_chunk.size(), in_single);
|
||||
std::get<I>(buffers) = in_chunk;
|
||||
arg_info.mode = ArgMode::Single;
|
||||
arg_info.mode = MaterializeArgMode::Single;
|
||||
}
|
||||
else if (common_info.type == CommonVArrayInfo::Type::Span) {
|
||||
/* Remember the span so that it doesn't have to be retrieved in every iteration. */
|
||||
|
@ -264,9 +268,9 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
|
|||
[&] {
|
||||
using ParamTag = ParamTags;
|
||||
using T = typename ParamTag::base_type;
|
||||
[[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
|
||||
[[maybe_unused]] MaterializeArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
|
||||
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
|
||||
if (arg_info.mode == ArgMode::Single) {
|
||||
if (arg_info.mode == MaterializeArgMode::Single) {
|
||||
/* The single value has been filled into a buffer already reused for every chunk. */
|
||||
return Span<T>(std::get<I>(buffers));
|
||||
}
|
||||
|
@ -276,7 +280,7 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
|
|||
/* In this case we can just use an existing span instead of "compressing" it into
|
||||
* a new temporary buffer. */
|
||||
const IndexRange sliced_mask_range = sliced_mask.as_range();
|
||||
arg_info.mode = ArgMode::Span;
|
||||
arg_info.mode = MaterializeArgMode::Span;
|
||||
return arg_info.internal_span.slice(sliced_mask_range);
|
||||
}
|
||||
}
|
||||
|
@ -287,11 +291,13 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
|
|||
varray_impl.materialize_compressed_to_uninitialized(sliced_mask, in_chunk.data());
|
||||
/* Remember that this parameter has been materialized, so that the values are
|
||||
* destructed properly when the chunk is done. */
|
||||
arg_info.mode = ArgMode::Materialized;
|
||||
arg_info.mode = MaterializeArgMode::Materialized;
|
||||
return Span<T>(in_chunk);
|
||||
}
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleOutput) {
|
||||
else if constexpr (ELEM(ParamTag::category,
|
||||
MFParamCategory::SingleOutput,
|
||||
MFParamCategory::SingleMutable)) {
|
||||
/* For outputs, just pass a pointer. This is important so that `__restrict` works. */
|
||||
return std::get<I>(loaded_params);
|
||||
}
|
||||
|
@ -303,9 +309,9 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
|
|||
/* Use `typedef` instead of `using` to work around a compiler bug. */
|
||||
typedef ParamTags ParamTag;
|
||||
typedef typename ParamTag::base_type T;
|
||||
[[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
|
||||
[[maybe_unused]] MaterializeArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
|
||||
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
|
||||
if (arg_info.mode == ArgMode::Materialized) {
|
||||
if (arg_info.mode == MaterializeArgMode::Materialized) {
|
||||
T *in_chunk = std::get<I>(buffers_owner).ptr();
|
||||
destruct_n(in_chunk, chunk_size);
|
||||
}
|
||||
|
@ -320,9 +326,9 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
|
|||
/* Use `typedef` instead of `using` to work around a compiler bug. */
|
||||
typedef ParamTags ParamTag;
|
||||
typedef typename ParamTag::base_type T;
|
||||
[[maybe_unused]] ArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
|
||||
[[maybe_unused]] MaterializeArgInfo<ParamTags> &arg_info = std::get<I>(args_info);
|
||||
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
|
||||
if (arg_info.mode == ArgMode::Single) {
|
||||
if (arg_info.mode == MaterializeArgMode::Single) {
|
||||
MutableSpan<T> in_chunk = std::get<I>(buffers);
|
||||
destruct_n(in_chunk.data(), in_chunk.size());
|
||||
}
|
||||
|
@ -330,272 +336,254 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
|
|||
}(),
|
||||
...);
|
||||
}
|
||||
} // namespace materialize_detail
|
||||
|
||||
template<typename... ParamTags> class CustomMF : public MultiFunction {
|
||||
private:
|
||||
std::function<void(IndexMask mask, MFParams params)> fn_;
|
||||
MFSignature signature_;
|
||||
template<typename ElementFn, typename ExecPreset, typename... ParamTags, size_t... I>
|
||||
inline void execute_element_fn_as_multi_function(const ElementFn element_fn,
|
||||
const ExecPreset exec_preset,
|
||||
const IndexMask mask,
|
||||
MFParams params,
|
||||
TypeSequence<ParamTags...> /*param_tags*/,
|
||||
std::index_sequence<I...> /*indices*/)
|
||||
{
|
||||
|
||||
using TagsSequence = TypeSequence<ParamTags...>;
|
||||
/* Load parameters from #MFParams. */
|
||||
/* Contains `const GVArrayImpl *` for inputs and `T *` for outputs. */
|
||||
const auto loaded_params = std::make_tuple([&]() {
|
||||
/* Use `typedef` instead of `using` to work around a compiler bug. */
|
||||
typedef ParamTags ParamTag;
|
||||
typedef typename ParamTag::base_type T;
|
||||
|
||||
public:
|
||||
template<typename ElementFn, typename ExecPreset = CustomMF_presets::Materialized>
|
||||
CustomMF(const char *name,
|
||||
ElementFn element_fn,
|
||||
ExecPreset exec_preset = CustomMF_presets::Materialized())
|
||||
{
|
||||
MFSignatureBuilder signature{name};
|
||||
add_signature_parameters(signature, std::make_index_sequence<TagsSequence::size()>());
|
||||
signature_ = signature.build();
|
||||
this->set_signature(&signature_);
|
||||
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
|
||||
return params.readonly_single_input(I).get_implementation();
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleOutput) {
|
||||
return static_cast<T *>(params.uninitialized_single_output(I).data());
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleMutable) {
|
||||
return static_cast<T *>(params.single_mutable(I).data());
|
||||
}
|
||||
}()...);
|
||||
|
||||
fn_ = [element_fn, exec_preset](IndexMask mask, MFParams params) {
|
||||
execute(
|
||||
element_fn, exec_preset, mask, params, std::make_index_sequence<TagsSequence::size()>());
|
||||
};
|
||||
/* Try execute devirtualized if enabled and the input types allow it. */
|
||||
bool executed_devirtualized = false;
|
||||
if constexpr (ExecPreset::use_devirtualization) {
|
||||
const auto devirtualizers = exec_preset.create_devirtualizers(
|
||||
TypeSequence<ParamTags...>(), std::index_sequence<I...>(), mask, loaded_params);
|
||||
executed_devirtualized = call_with_devirtualized_parameters(
|
||||
devirtualizers, [&](auto &&...args) {
|
||||
execute_array(TypeSequence<ParamTags...>(),
|
||||
std::index_sequence<I...>(),
|
||||
element_fn,
|
||||
std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename ElementFn, typename ExecPreset, size_t... I>
|
||||
static void execute(ElementFn element_fn,
|
||||
ExecPreset exec_preset,
|
||||
IndexMask mask,
|
||||
MFParams params,
|
||||
std::index_sequence<I...> /*indices*/)
|
||||
{
|
||||
/* Contains `const GVArrayImpl *` for inputs and `T *` for outputs. */
|
||||
const auto loaded_params = std::make_tuple([&]() {
|
||||
/* Use `typedef` instead of `using` to work around a compiler bug. */
|
||||
typedef typename TagsSequence::template at_index<I> ParamTag;
|
||||
typedef typename ParamTag::base_type T;
|
||||
|
||||
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
|
||||
return params.readonly_single_input(I).get_implementation();
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleOutput) {
|
||||
return static_cast<T *>(params.uninitialized_single_output(I).data());
|
||||
}
|
||||
}()...);
|
||||
|
||||
/* First try devirtualized execution, since this is the most efficient. */
|
||||
bool executed_devirtualized = false;
|
||||
if constexpr (ExecPreset::use_devirtualization) {
|
||||
const auto devirtualizers = exec_preset.create_devirtualizers(
|
||||
TagsSequence(), std::index_sequence<I...>(), mask, loaded_params);
|
||||
executed_devirtualized = call_with_devirtualized_parameters(
|
||||
devirtualizers, [&](auto &&...args) {
|
||||
detail::execute_array(TagsSequence(),
|
||||
std::index_sequence<I...>(),
|
||||
element_fn,
|
||||
std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
/* If devirtualized execution was disabled or not possible, use a fallback method which is
|
||||
* slower but always works. */
|
||||
if (!executed_devirtualized) {
|
||||
/* The materialized method is most common because it avoids most virtual function overhead but
|
||||
* still instantiates the function only once. */
|
||||
if constexpr (ExecPreset::fallback_mode == exec_presets::FallbackMode::Materialized) {
|
||||
execute_materialized(TypeSequence<ParamTags...>(),
|
||||
std::index_sequence<I...>(),
|
||||
element_fn,
|
||||
mask,
|
||||
loaded_params);
|
||||
}
|
||||
|
||||
/* If devirtualized execution was disabled or not possible, use a fallback method which is
|
||||
* slower but always works. */
|
||||
if (!executed_devirtualized) {
|
||||
if constexpr (ExecPreset::fallback_mode == CustomMF_presets::FallbackMode::Materialized) {
|
||||
materialize_detail::execute_materialized(
|
||||
TagsSequence(), std::index_sequence<I...>(), element_fn, mask, loaded_params);
|
||||
}
|
||||
else {
|
||||
detail::execute_array(
|
||||
TagsSequence(), std::index_sequence<I...>(), element_fn, mask, [&]() {
|
||||
/* Use `typedef` instead of `using` to work around a compiler bug. */
|
||||
typedef typename TagsSequence::template at_index<I> ParamTag;
|
||||
typedef typename ParamTag::base_type T;
|
||||
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
|
||||
const GVArrayImpl &varray_impl = *std::get<I>(loaded_params);
|
||||
return GVArray(&varray_impl).typed<T>();
|
||||
}
|
||||
else if constexpr (ParamTag::category == MFParamCategory::SingleOutput) {
|
||||
T *ptr = std::get<I>(loaded_params);
|
||||
return ptr;
|
||||
}
|
||||
}()...);
|
||||
}
|
||||
else {
|
||||
/* This fallback is slower because it uses virtual method calls for every element. */
|
||||
execute_array(
|
||||
TypeSequence<ParamTags...>(), std::index_sequence<I...>(), element_fn, mask, [&]() {
|
||||
/* Use `typedef` instead of `using` to work around a compiler bug. */
|
||||
typedef ParamTags ParamTag;
|
||||
typedef typename ParamTag::base_type T;
|
||||
if constexpr (ParamTag::category == MFParamCategory::SingleInput) {
|
||||
const GVArrayImpl &varray_impl = *std::get<I>(loaded_params);
|
||||
return GVArray(&varray_impl).typed<T>();
|
||||
}
|
||||
else if constexpr (ELEM(ParamTag::category,
|
||||
MFParamCategory::SingleOutput,
|
||||
MFParamCategory::SingleMutable)) {
|
||||
T *ptr = std::get<I>(loaded_params);
|
||||
return ptr;
|
||||
}
|
||||
}()...);
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t... I>
|
||||
static void add_signature_parameters(MFSignatureBuilder &signature,
|
||||
std::index_sequence<I...> /* indices */)
|
||||
{
|
||||
(
|
||||
/* Loop over all parameter types and add an entry for each in the signature. */
|
||||
[&] {
|
||||
/* Use `typedef` instead of `using` to work around a compiler bug. */
|
||||
typedef typename TagsSequence::template at_index<I> ParamTag;
|
||||
signature.add(ParamTag(), "");
|
||||
}(),
|
||||
...);
|
||||
}
|
||||
|
||||
void call(IndexMask mask, MFParams params, MFContext /*context*/) const override
|
||||
{
|
||||
fn_(mask, params);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a multi-function with the following parameters:
|
||||
* 1. single input (SI) of type In1
|
||||
* 2. single output (SO) of type Out1
|
||||
*
|
||||
* This example creates a function that adds 10 to the incoming values:
|
||||
* `CustomMF_SI_SO<int, int> fn("add 10", [](int value) { return value + 10; });`
|
||||
* `element_fn` is expected to return nothing and to have the following parameters:
|
||||
* - For single-inputs: const value or reference.
|
||||
* - For single-mutables: non-const reference.
|
||||
* - For single-outputs: non-const pointer.
|
||||
*/
|
||||
template<typename In1, typename Out1>
|
||||
class CustomMF_SI_SO : public CustomMF<MFParamTag<MFParamCategory::SingleInput, In1>,
|
||||
MFParamTag<MFParamCategory::SingleOutput, Out1>> {
|
||||
public:
|
||||
template<typename ElementFn, typename ExecPreset = CustomMF_presets::Materialized>
|
||||
CustomMF_SI_SO(const char *name,
|
||||
ElementFn element_fn,
|
||||
ExecPreset exec_preset = CustomMF_presets::Materialized())
|
||||
: CustomMF<MFParamTag<MFParamCategory::SingleInput, In1>,
|
||||
MFParamTag<MFParamCategory::SingleOutput, Out1>>(
|
||||
name,
|
||||
[element_fn](const In1 &in1, Out1 *out1) { new (out1) Out1(element_fn(in1)); },
|
||||
exec_preset)
|
||||
{
|
||||
}
|
||||
};
|
||||
template<typename ElementFn, typename ExecPreset, typename... ParamTags>
|
||||
inline auto build_multi_function_call_from_element_fn(const ElementFn element_fn,
|
||||
const ExecPreset exec_preset,
|
||||
TypeSequence<ParamTags...> /*param_tags*/)
|
||||
{
|
||||
return [element_fn, exec_preset](const IndexMask mask, MFParams params) {
|
||||
execute_element_fn_as_multi_function(element_fn,
|
||||
exec_preset,
|
||||
mask,
|
||||
params,
|
||||
TypeSequence<ParamTags...>(),
|
||||
std::make_index_sequence<sizeof...(ParamTags)>());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a multi-function with the following parameters:
|
||||
* 1. single input (SI) of type In1
|
||||
* 2. single input (SI) of type In2
|
||||
* 3. single output (SO) of type Out1
|
||||
* A multi function that just invokes the provided function in its #call method.
|
||||
*/
|
||||
template<typename In1, typename In2, typename Out1>
|
||||
class CustomMF_SI_SI_SO : public CustomMF<MFParamTag<MFParamCategory::SingleInput, In1>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In2>,
|
||||
MFParamTag<MFParamCategory::SingleOutput, Out1>> {
|
||||
public:
|
||||
template<typename ElementFn, typename ExecPreset = CustomMF_presets::Materialized>
|
||||
CustomMF_SI_SI_SO(const char *name,
|
||||
ElementFn element_fn,
|
||||
ExecPreset exec_preset = CustomMF_presets::Materialized())
|
||||
: CustomMF<MFParamTag<MFParamCategory::SingleInput, In1>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In2>,
|
||||
MFParamTag<MFParamCategory::SingleOutput, Out1>>(
|
||||
name,
|
||||
[element_fn](const In1 &in1, const In2 &in2, Out1 *out1) {
|
||||
new (out1) Out1(element_fn(in1, in2));
|
||||
},
|
||||
exec_preset)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a multi-function with the following parameters:
|
||||
* 1. single input (SI) of type In1
|
||||
* 2. single input (SI) of type In2
|
||||
* 3. single input (SI) of type In3
|
||||
* 4. single output (SO) of type Out1
|
||||
*/
|
||||
template<typename In1, typename In2, typename In3, typename Out1>
|
||||
class CustomMF_SI_SI_SI_SO : public CustomMF<MFParamTag<MFParamCategory::SingleInput, In1>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In2>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In3>,
|
||||
MFParamTag<MFParamCategory::SingleOutput, Out1>> {
|
||||
public:
|
||||
template<typename ElementFn, typename ExecPreset = CustomMF_presets::Materialized>
|
||||
CustomMF_SI_SI_SI_SO(const char *name,
|
||||
ElementFn element_fn,
|
||||
ExecPreset exec_preset = CustomMF_presets::Materialized())
|
||||
: CustomMF<MFParamTag<MFParamCategory::SingleInput, In1>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In2>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In3>,
|
||||
MFParamTag<MFParamCategory::SingleOutput, Out1>>(
|
||||
name,
|
||||
[element_fn](const In1 &in1, const In2 &in2, const In3 &in3, Out1 *out1) {
|
||||
new (out1) Out1(element_fn(in1, in2, in3));
|
||||
},
|
||||
exec_preset)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a multi-function with the following parameters:
|
||||
* 1. single input (SI) of type In1
|
||||
* 2. single input (SI) of type In2
|
||||
* 3. single input (SI) of type In3
|
||||
* 4. single input (SI) of type In4
|
||||
* 5. single output (SO) of type Out1
|
||||
*/
|
||||
template<typename In1, typename In2, typename In3, typename In4, typename Out1>
|
||||
class CustomMF_SI_SI_SI_SI_SO : public CustomMF<MFParamTag<MFParamCategory::SingleInput, In1>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In2>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In3>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In4>,
|
||||
MFParamTag<MFParamCategory::SingleOutput, Out1>> {
|
||||
public:
|
||||
template<typename ElementFn, typename ExecPreset = CustomMF_presets::Materialized>
|
||||
CustomMF_SI_SI_SI_SI_SO(const char *name,
|
||||
ElementFn element_fn,
|
||||
ExecPreset exec_preset = CustomMF_presets::Materialized())
|
||||
: CustomMF<MFParamTag<MFParamCategory::SingleInput, In1>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In2>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In3>,
|
||||
MFParamTag<MFParamCategory::SingleInput, In4>,
|
||||
MFParamTag<MFParamCategory::SingleOutput, Out1>>(
|
||||
name,
|
||||
[element_fn](
|
||||
const In1 &in1, const In2 &in2, const In3 &in3, const In4 &in4, Out1 *out1) {
|
||||
new (out1) Out1(element_fn(in1, in2, in3, in4));
|
||||
},
|
||||
exec_preset)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a multi-function with the following parameters:
|
||||
* 1. single mutable (SM) of type Mut1
|
||||
*/
|
||||
template<typename Mut1> class CustomMF_SM : public MultiFunction {
|
||||
template<typename CallFn, typename... ParamTags> class CustomMF : public MultiFunction {
|
||||
private:
|
||||
using FunctionT = std::function<void(IndexMask, MutableSpan<Mut1>)>;
|
||||
FunctionT function_;
|
||||
MFSignature signature_;
|
||||
CallFn call_fn_;
|
||||
|
||||
public:
|
||||
CustomMF_SM(const char *name, FunctionT function) : function_(std::move(function))
|
||||
CustomMF(const char *name, CallFn call_fn, TypeSequence<ParamTags...> /*param_tags*/)
|
||||
: call_fn_(std::move(call_fn))
|
||||
{
|
||||
MFSignatureBuilder signature{name};
|
||||
signature.single_mutable<Mut1>("Mut1");
|
||||
/* Loop over all parameter types and add an entry for each in the signature. */
|
||||
([&] { signature.add(ParamTags(), ""); }(), ...);
|
||||
signature_ = signature.build();
|
||||
this->set_signature(&signature_);
|
||||
}
|
||||
|
||||
template<typename ElementFuncT>
|
||||
CustomMF_SM(const char *name, ElementFuncT element_fn)
|
||||
: CustomMF_SM(name, CustomMF_SM::create_function(element_fn))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn)
|
||||
{
|
||||
return [=](IndexMask mask, MutableSpan<Mut1> mut1) {
|
||||
mask.to_best_mask_type([&](const auto &mask) {
|
||||
for (const int64_t i : mask) {
|
||||
element_fn(mut1[i]);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
void call(IndexMask mask, MFParams params, MFContext /*context*/) const override
|
||||
{
|
||||
MutableSpan<Mut1> mut1 = params.single_mutable<Mut1>(0);
|
||||
function_(mask, mut1);
|
||||
call_fn_(mask, params);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Out, typename... In, typename ElementFn, typename ExecPreset>
|
||||
inline auto build_multi_function_with_n_inputs_one_output(const char *name,
|
||||
const ElementFn element_fn,
|
||||
const ExecPreset exec_preset,
|
||||
TypeSequence<In...> /*in_types*/)
|
||||
{
|
||||
constexpr auto param_tags = TypeSequence<MFParamTag<MFParamCategory::SingleInput, In>...,
|
||||
MFParamTag<MFParamCategory::SingleOutput, Out>>();
|
||||
auto call_fn = build_multi_function_call_from_element_fn(
|
||||
[element_fn](const In &...in, Out *out) { new (out) Out(element_fn(in...)); },
|
||||
exec_preset,
|
||||
param_tags);
|
||||
return CustomMF(name, call_fn, param_tags);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Build multi-function with 1 single-input and 1 single-output parameter. */
|
||||
template<typename In1,
|
||||
typename Out1,
|
||||
typename ElementFn,
|
||||
typename ExecPreset = exec_presets::Materialized>
|
||||
inline auto SI1_SO(const char *name,
|
||||
const ElementFn element_fn,
|
||||
const ExecPreset exec_preset = exec_presets::Materialized())
|
||||
{
|
||||
return detail::build_multi_function_with_n_inputs_one_output<Out1>(
|
||||
name, element_fn, exec_preset, TypeSequence<In1>());
|
||||
}
|
||||
|
||||
/** Build multi-function with 2 single-input and 1 single-output parameter. */
|
||||
template<typename In1,
|
||||
typename In2,
|
||||
typename Out1,
|
||||
typename ElementFn,
|
||||
typename ExecPreset = exec_presets::Materialized>
|
||||
inline auto SI2_SO(const char *name,
|
||||
const ElementFn element_fn,
|
||||
const ExecPreset exec_preset = exec_presets::Materialized())
|
||||
{
|
||||
return detail::build_multi_function_with_n_inputs_one_output<Out1>(
|
||||
name, element_fn, exec_preset, TypeSequence<In1, In2>());
|
||||
}
|
||||
|
||||
/** Build multi-function with 3 single-input and 1 single-output parameter. */
|
||||
template<typename In1,
|
||||
typename In2,
|
||||
typename In3,
|
||||
typename Out1,
|
||||
typename ElementFn,
|
||||
typename ExecPreset = exec_presets::Materialized>
|
||||
inline auto SI3_SO(const char *name,
|
||||
const ElementFn element_fn,
|
||||
const ExecPreset exec_preset = exec_presets::Materialized())
|
||||
{
|
||||
return detail::build_multi_function_with_n_inputs_one_output<Out1>(
|
||||
name, element_fn, exec_preset, TypeSequence<In1, In2, In3>());
|
||||
}
|
||||
|
||||
/** Build multi-function with 4 single-input and 1 single-output parameter. */
|
||||
template<typename In1,
|
||||
typename In2,
|
||||
typename In3,
|
||||
typename In4,
|
||||
typename Out1,
|
||||
typename ElementFn,
|
||||
typename ExecPreset = exec_presets::Materialized>
|
||||
inline auto SI4_SO(const char *name,
|
||||
const ElementFn element_fn,
|
||||
const ExecPreset exec_preset = exec_presets::Materialized())
|
||||
{
|
||||
return detail::build_multi_function_with_n_inputs_one_output<Out1>(
|
||||
name, element_fn, exec_preset, TypeSequence<In1, In2, In3, In4>());
|
||||
}
|
||||
|
||||
/** Build multi-function with 5 single-input and 1 single-output parameter. */
|
||||
template<typename In1,
|
||||
typename In2,
|
||||
typename In3,
|
||||
typename In4,
|
||||
typename In5,
|
||||
typename Out1,
|
||||
typename ElementFn,
|
||||
typename ExecPreset = exec_presets::Materialized>
|
||||
inline auto SI5_SO(const char *name,
|
||||
const ElementFn element_fn,
|
||||
const ExecPreset exec_preset = exec_presets::Materialized())
|
||||
{
|
||||
return detail::build_multi_function_with_n_inputs_one_output<Out1>(
|
||||
name, element_fn, exec_preset, TypeSequence<In1, In2, In3, In4, In5>());
|
||||
}
|
||||
|
||||
/** Build multi-function with 6 single-input and 1 single-output parameter. */
|
||||
template<typename In1,
|
||||
typename In2,
|
||||
typename In3,
|
||||
typename In4,
|
||||
typename In5,
|
||||
typename In6,
|
||||
typename Out1,
|
||||
typename ElementFn,
|
||||
typename ExecPreset = exec_presets::Materialized>
|
||||
inline auto SI6_SO(const char *name,
|
||||
const ElementFn element_fn,
|
||||
const ExecPreset exec_preset = exec_presets::Materialized())
|
||||
{
|
||||
return detail::build_multi_function_with_n_inputs_one_output<Out1>(
|
||||
name, element_fn, exec_preset, TypeSequence<In1, In2, In3, In4, In5, In6>());
|
||||
}
|
||||
|
||||
/** Build multi-function with 1 single-mutable parameter. */
|
||||
template<typename Mut1, typename ElementFn, typename ExecPreset = exec_presets::AllSpanOrSingle>
|
||||
inline auto SM(const char *name,
|
||||
const ElementFn element_fn,
|
||||
const ExecPreset exec_preset = exec_presets::AllSpanOrSingle())
|
||||
{
|
||||
constexpr auto param_tags = TypeSequence<MFParamTag<MFParamCategory::SingleMutable, Mut1>>();
|
||||
auto call_fn = detail::build_multi_function_call_from_element_fn(
|
||||
element_fn, exec_preset, param_tags);
|
||||
return detail::CustomMF(name, call_fn, param_tags);
|
||||
}
|
||||
|
||||
} // namespace blender::fn::build_mf
|
||||
|
||||
namespace blender::fn {
|
||||
|
||||
/**
|
||||
* A multi-function that outputs the same value every time. The value is not owned by an instance
|
||||
* of this function. If #make_value_copy is false, the caller is responsible for destructing and
|
||||
|
|
|
@ -519,8 +519,8 @@ GField make_field_constant_if_possible(GField field)
|
|||
|
||||
Field<bool> invert_boolean_field(const Field<bool> &field)
|
||||
{
|
||||
static CustomMF_SI_SO<bool, bool> not_fn{
|
||||
"Not", [](bool a) { return !a; }, CustomMF_presets::AllSpanOrSingle()};
|
||||
static auto not_fn = build_mf::SI1_SO<bool, bool>(
|
||||
"Not", [](bool a) { return !a; }, build_mf::exec_presets::AllSpanOrSingle());
|
||||
auto not_op = std::make_shared<FieldOperation>(FieldOperation(not_fn, {field}));
|
||||
return Field<bool>(not_op);
|
||||
}
|
||||
|
|
|
@ -104,11 +104,9 @@ TEST(field, InputAndFunction)
|
|||
{
|
||||
GField index_field{std::make_shared<IndexFieldInput>()};
|
||||
|
||||
std::unique_ptr<MultiFunction> add_fn = std::make_unique<CustomMF_SI_SI_SO<int, int, int>>(
|
||||
"add", [](int a, int b) { return a + b; });
|
||||
GField output_field{std::make_shared<FieldOperation>(
|
||||
FieldOperation(std::move(add_fn), {index_field, index_field})),
|
||||
0};
|
||||
auto add_fn = build_mf::SI2_SO<int, int, int>("add", [](int a, int b) { return a + b; });
|
||||
GField output_field{
|
||||
std::make_shared<FieldOperation>(FieldOperation(add_fn, {index_field, index_field})), 0};
|
||||
|
||||
Array<int> result(10);
|
||||
|
||||
|
@ -129,16 +127,12 @@ TEST(field, TwoFunctions)
|
|||
{
|
||||
GField index_field{std::make_shared<IndexFieldInput>()};
|
||||
|
||||
std::unique_ptr<MultiFunction> add_fn = std::make_unique<CustomMF_SI_SI_SO<int, int, int>>(
|
||||
"add", [](int a, int b) { return a + b; });
|
||||
GField add_field{std::make_shared<FieldOperation>(
|
||||
FieldOperation(std::move(add_fn), {index_field, index_field})),
|
||||
0};
|
||||
auto add_fn = build_mf::SI2_SO<int, int, int>("add", [](int a, int b) { return a + b; });
|
||||
GField add_field{
|
||||
std::make_shared<FieldOperation>(FieldOperation(add_fn, {index_field, index_field})), 0};
|
||||
|
||||
std::unique_ptr<MultiFunction> add_10_fn = std::make_unique<CustomMF_SI_SO<int, int>>(
|
||||
"add_10", [](int a) { return a + 10; });
|
||||
GField result_field{
|
||||
std::make_shared<FieldOperation>(FieldOperation(std::move(add_10_fn), {add_field})), 0};
|
||||
auto add_10_fn = build_mf::SI1_SO<int, int>("add_10", [](int a) { return a + 10; });
|
||||
GField result_field{std::make_shared<FieldOperation>(FieldOperation(add_10_fn, {add_field})), 0};
|
||||
|
||||
Array<int> result(10);
|
||||
|
||||
|
@ -230,11 +224,9 @@ TEST(field, TwoFunctionsTwoOutputs)
|
|||
Field<int> result_field_1{fn, 0};
|
||||
Field<int> intermediate_field{fn, 1};
|
||||
|
||||
std::unique_ptr<MultiFunction> add_10_fn = std::make_unique<CustomMF_SI_SO<int, int>>(
|
||||
"add_10", [](int a) { return a + 10; });
|
||||
auto add_10_fn = build_mf::SI1_SO<int, int>("add_10", [](int a) { return a + 10; });
|
||||
Field<int> result_field_2{
|
||||
std::make_shared<FieldOperation>(FieldOperation(std::move(add_10_fn), {intermediate_field})),
|
||||
0};
|
||||
std::make_shared<FieldOperation>(FieldOperation(add_10_fn, {intermediate_field})), 0};
|
||||
|
||||
FieldContext field_context;
|
||||
FieldEvaluator field_evaluator{field_context, &mask};
|
||||
|
|
|
@ -19,7 +19,7 @@ TEST(multi_function_procedure, ConstantOutput)
|
|||
*/
|
||||
|
||||
CustomMF_Constant<int> constant_fn{5};
|
||||
CustomMF_SI_SI_SO<int, int, int> add_fn{"Add", [](int a, int b) { return a + b; }};
|
||||
auto add_fn = build_mf::SI2_SO<int, int, int>("Add", [](int a, int b) { return a + b; });
|
||||
|
||||
MFProcedure procedure;
|
||||
MFProcedureBuilder builder{procedure};
|
||||
|
@ -56,8 +56,8 @@ TEST(multi_function_procedure, SimpleTest)
|
|||
* }
|
||||
*/
|
||||
|
||||
CustomMF_SI_SI_SO<int, int, int> add_fn{"add", [](int a, int b) { return a + b; }};
|
||||
CustomMF_SM<int> add_10_fn{"add_10", [](int &a) { a += 10; }};
|
||||
auto add_fn = fn::build_mf::SI2_SO<int, int, int>("add", [](int a, int b) { return a + b; });
|
||||
auto add_10_fn = fn::build_mf::SM<int>("add_10", [](int &a) { a += 10; });
|
||||
|
||||
MFProcedure procedure;
|
||||
MFProcedureBuilder builder{procedure};
|
||||
|
@ -106,8 +106,8 @@ TEST(multi_function_procedure, BranchTest)
|
|||
* }
|
||||
*/
|
||||
|
||||
CustomMF_SM<int> add_10_fn{"add_10", [](int &a) { a += 10; }};
|
||||
CustomMF_SM<int> add_100_fn{"add_100", [](int &a) { a += 100; }};
|
||||
auto add_10_fn = build_mf::SM<int>("add_10", [](int &a) { a += 10; });
|
||||
auto add_100_fn = build_mf::SM<int>("add_100", [](int &a) { a += 100; });
|
||||
|
||||
MFProcedure procedure;
|
||||
MFProcedureBuilder builder{procedure};
|
||||
|
@ -153,10 +153,10 @@ TEST(multi_function_procedure, EvaluateOne)
|
|||
*/
|
||||
|
||||
int tot_evaluations = 0;
|
||||
CustomMF_SI_SO<int, int> add_10_fn{"add_10", [&](int a) {
|
||||
tot_evaluations++;
|
||||
return a + 10;
|
||||
}};
|
||||
const auto add_10_fn = fn::build_mf::SI1_SO<int, int>("add_10", [&](int a) {
|
||||
tot_evaluations++;
|
||||
return a + 10;
|
||||
});
|
||||
|
||||
MFProcedure procedure;
|
||||
MFProcedureBuilder builder{procedure};
|
||||
|
@ -205,11 +205,11 @@ TEST(multi_function_procedure, SimpleLoop)
|
|||
|
||||
CustomMF_Constant<int> const_1_fn{1};
|
||||
CustomMF_Constant<int> const_0_fn{0};
|
||||
CustomMF_SI_SI_SO<int, int, bool> greater_or_equal_fn{"greater or equal",
|
||||
[](int a, int b) { return a >= b; }};
|
||||
CustomMF_SM<int> double_fn{"double", [](int &a) { a *= 2; }};
|
||||
CustomMF_SM<int> add_1000_fn{"add 1000", [](int &a) { a += 1000; }};
|
||||
CustomMF_SM<int> add_1_fn{"add 1", [](int &a) { a += 1; }};
|
||||
auto greater_or_equal_fn = fn::build_mf::SI2_SO<int, int, bool>(
|
||||
"greater or equal", [](int a, int b) { return a >= b; });
|
||||
auto double_fn = build_mf::SM<int>("double", [](int &a) { a *= 2; });
|
||||
auto add_1000_fn = build_mf::SM<int>("add 1000", [](int &a) { a += 1000; });
|
||||
auto add_1_fn = build_mf::SM<int>("add 1", [](int &a) { a += 1; });
|
||||
|
||||
MFProcedure procedure;
|
||||
MFProcedureBuilder builder{procedure};
|
||||
|
@ -338,7 +338,7 @@ TEST(multi_function_procedure, BufferReuse)
|
|||
* }
|
||||
*/
|
||||
|
||||
CustomMF_SI_SO<int, int> add_10_fn{"add 10", [](int a) { return a + 10; }};
|
||||
auto add_10_fn = build_mf::SI1_SO<int, int>("add 10", [](int a) { return a + 10; });
|
||||
|
||||
MFProcedure procedure;
|
||||
MFProcedureBuilder builder{procedure};
|
||||
|
|
|
@ -149,98 +149,6 @@ TEST(multi_function, GenericAppendFunction)
|
|||
EXPECT_EQ(vectors_ref[3][0], 1);
|
||||
}
|
||||
|
||||
TEST(multi_function, CustomMF_SI_SO)
|
||||
{
|
||||
CustomMF_SI_SO<std::string, uint> fn("strlen",
|
||||
[](const std::string &str) { return str.size(); });
|
||||
|
||||
Array<std::string> strings = {"hello", "world", "test", "another test"};
|
||||
Array<uint> sizes(strings.size(), 0);
|
||||
|
||||
MFParamsBuilder params(fn, strings.size());
|
||||
params.add_readonly_single_input(strings.as_span());
|
||||
params.add_uninitialized_single_output(sizes.as_mutable_span());
|
||||
|
||||
MFContextBuilder context;
|
||||
|
||||
fn.call(IndexRange(strings.size()), params, context);
|
||||
|
||||
EXPECT_EQ(sizes[0], 5);
|
||||
EXPECT_EQ(sizes[1], 5);
|
||||
EXPECT_EQ(sizes[2], 4);
|
||||
EXPECT_EQ(sizes[3], 12);
|
||||
}
|
||||
|
||||
TEST(multi_function, CustomMF_SI_SI_SO)
|
||||
{
|
||||
CustomMF_SI_SI_SO<int, int, int> fn("mul", [](int a, int b) { return a * b; });
|
||||
|
||||
Array<int> values_a = {4, 6, 8, 9};
|
||||
int value_b = 10;
|
||||
Array<int> outputs(values_a.size(), -1);
|
||||
|
||||
MFParamsBuilder params(fn, values_a.size());
|
||||
params.add_readonly_single_input(values_a.as_span());
|
||||
params.add_readonly_single_input(&value_b);
|
||||
params.add_uninitialized_single_output(outputs.as_mutable_span());
|
||||
|
||||
MFContextBuilder context;
|
||||
|
||||
fn.call({0, 1, 3}, params, context);
|
||||
|
||||
EXPECT_EQ(outputs[0], 40);
|
||||
EXPECT_EQ(outputs[1], 60);
|
||||
EXPECT_EQ(outputs[2], -1);
|
||||
EXPECT_EQ(outputs[3], 90);
|
||||
}
|
||||
|
||||
TEST(multi_function, CustomMF_SI_SI_SI_SO)
|
||||
{
|
||||
CustomMF_SI_SI_SI_SO<int, std::string, bool, uint> fn{
|
||||
"custom",
|
||||
[](int a, const std::string &b, bool c) { return uint(uint(a) + b.size() + uint(c)); }};
|
||||
|
||||
Array<int> values_a = {5, 7, 3, 8};
|
||||
Array<std::string> values_b = {"hello", "world", "another", "test"};
|
||||
Array<bool> values_c = {true, false, false, true};
|
||||
Array<uint> outputs(values_a.size(), 0);
|
||||
|
||||
MFParamsBuilder params(fn, values_a.size());
|
||||
params.add_readonly_single_input(values_a.as_span());
|
||||
params.add_readonly_single_input(values_b.as_span());
|
||||
params.add_readonly_single_input(values_c.as_span());
|
||||
params.add_uninitialized_single_output(outputs.as_mutable_span());
|
||||
|
||||
MFContextBuilder context;
|
||||
|
||||
fn.call({1, 2, 3}, params, context);
|
||||
|
||||
EXPECT_EQ(outputs[0], 0);
|
||||
EXPECT_EQ(outputs[1], 12);
|
||||
EXPECT_EQ(outputs[2], 10);
|
||||
EXPECT_EQ(outputs[3], 13);
|
||||
}
|
||||
|
||||
TEST(multi_function, CustomMF_SM)
|
||||
{
|
||||
CustomMF_SM<std::string> fn("AddSuffix", [](std::string &value) { value += " test"; });
|
||||
|
||||
Array<std::string> values = {"a", "b", "c", "d", "e"};
|
||||
|
||||
MFParamsBuilder params(fn, values.size());
|
||||
params.add_single_mutable(values.as_mutable_span());
|
||||
|
||||
MFContextBuilder context;
|
||||
|
||||
fn.call({1, 2, 3}, params, context);
|
||||
|
||||
EXPECT_EQ(values[0], "a");
|
||||
EXPECT_EQ(values[1], "b test");
|
||||
EXPECT_EQ(values[2], "c test");
|
||||
EXPECT_EQ(values[3], "d test");
|
||||
EXPECT_EQ(values[4], "e");
|
||||
}
|
||||
|
||||
TEST(multi_function, CustomMF_Constant)
|
||||
{
|
||||
CustomMF_Constant<int> fn{42};
|
||||
|
|
|
@ -17,10 +17,10 @@ namespace blender::geometry {
|
|||
|
||||
static fn::Field<int> get_count_input_max_one(const fn::Field<int> &count_field)
|
||||
{
|
||||
static fn::CustomMF_SI_SO<int, int> max_one_fn(
|
||||
static auto max_one_fn = fn::build_mf::SI1_SO<int, int>(
|
||||
"Clamp Above One",
|
||||
[](int value) { return std::max(1, value); },
|
||||
fn::CustomMF_presets::AllSpanOrSingle());
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
auto clamp_op = std::make_shared<fn::FieldOperation>(
|
||||
fn::FieldOperation(max_one_fn, {count_field}));
|
||||
|
||||
|
@ -29,7 +29,7 @@ static fn::Field<int> get_count_input_max_one(const fn::Field<int> &count_field)
|
|||
|
||||
static fn::Field<int> get_count_input_from_length(const fn::Field<float> &length_field)
|
||||
{
|
||||
static fn::CustomMF_SI_SI_SO<float, float, int> get_count_fn(
|
||||
static auto get_count_fn = fn::build_mf::SI2_SO<float, float, int>(
|
||||
"Length Input to Count",
|
||||
[](const float curve_length, const float sample_length) {
|
||||
/* Find the number of sampled segments by dividing the total length by
|
||||
|
@ -37,7 +37,7 @@ static fn::Field<int> get_count_input_from_length(const fn::Field<float> &length
|
|||
const int count = int(curve_length / sample_length) + 1;
|
||||
return std::max(1, count);
|
||||
},
|
||||
fn::CustomMF_presets::AllSpanOrSingle());
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
|
||||
auto get_count_op = std::make_shared<fn::FieldOperation>(fn::FieldOperation(
|
||||
get_count_fn,
|
||||
|
|
|
@ -51,8 +51,8 @@ inline bool try_dispatch_float_math_fl_to_fl(const int operation, Callback &&cal
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto exec_preset_fast = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::CustomMF_presets::Materialized();
|
||||
static auto exec_preset_fast = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::build_mf::exec_presets::Materialized();
|
||||
|
||||
/* This is just an utility function to keep the individual cases smaller. */
|
||||
auto dispatch = [&](auto exec_preset, auto math_function) -> bool {
|
||||
|
@ -118,8 +118,8 @@ inline bool try_dispatch_float_math_fl_fl_to_fl(const int operation, Callback &&
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto exec_preset_fast = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::CustomMF_presets::Materialized();
|
||||
static auto exec_preset_fast = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::build_mf::exec_presets::Materialized();
|
||||
|
||||
/* This is just an utility function to keep the individual cases smaller. */
|
||||
auto dispatch = [&](auto exec_preset, auto math_function) -> bool {
|
||||
|
@ -180,21 +180,21 @@ inline bool try_dispatch_float_math_fl_fl_fl_to_fl(const int operation, Callback
|
|||
|
||||
switch (operation) {
|
||||
case NODE_MATH_MULTIPLY_ADD:
|
||||
return dispatch(fn::CustomMF_presets::AllSpanOrSingle(),
|
||||
return dispatch(fn::build_mf::exec_presets::AllSpanOrSingle(),
|
||||
[](float a, float b, float c) { return a * b + c; });
|
||||
case NODE_MATH_COMPARE:
|
||||
return dispatch(fn::CustomMF_presets::SomeSpanOrSingle<0, 1>(),
|
||||
return dispatch(fn::build_mf::exec_presets::SomeSpanOrSingle<0, 1>(),
|
||||
[](float a, float b, float c) -> float {
|
||||
return ((a == b) || (fabsf(a - b) <= fmaxf(c, FLT_EPSILON))) ? 1.0f : 0.0f;
|
||||
});
|
||||
case NODE_MATH_SMOOTH_MIN:
|
||||
return dispatch(fn::CustomMF_presets::SomeSpanOrSingle<0, 1>(),
|
||||
return dispatch(fn::build_mf::exec_presets::SomeSpanOrSingle<0, 1>(),
|
||||
[](float a, float b, float c) { return smoothminf(a, b, c); });
|
||||
case NODE_MATH_SMOOTH_MAX:
|
||||
return dispatch(fn::CustomMF_presets::SomeSpanOrSingle<0, 1>(),
|
||||
return dispatch(fn::build_mf::exec_presets::SomeSpanOrSingle<0, 1>(),
|
||||
[](float a, float b, float c) { return -smoothminf(-a, -b, c); });
|
||||
case NODE_MATH_WRAP:
|
||||
return dispatch(fn::CustomMF_presets::SomeSpanOrSingle<0>(),
|
||||
return dispatch(fn::build_mf::exec_presets::SomeSpanOrSingle<0>(),
|
||||
[](float a, float b, float c) { return wrapf(a, b, c); });
|
||||
}
|
||||
return false;
|
||||
|
@ -214,8 +214,8 @@ inline bool try_dispatch_float_math_fl3_fl3_to_fl3(const NodeVectorMathOperation
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto exec_preset_fast = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::CustomMF_presets::Materialized();
|
||||
static auto exec_preset_fast = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::build_mf::exec_presets::Materialized();
|
||||
|
||||
/* This is just a utility function to keep the individual cases smaller. */
|
||||
auto dispatch = [&](auto exec_preset, auto math_function) -> bool {
|
||||
|
@ -269,7 +269,7 @@ inline bool try_dispatch_float_math_fl3_fl3_to_fl(const NodeVectorMathOperation
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto exec_preset_fast = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_fast = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
|
||||
/* This is just a utility function to keep the individual cases smaller. */
|
||||
auto dispatch = [&](auto exec_preset, auto math_function) -> bool {
|
||||
|
@ -302,8 +302,8 @@ inline bool try_dispatch_float_math_fl3_fl3_fl3_to_fl3(const NodeVectorMathOpera
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto exec_preset_fast = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::CustomMF_presets::Materialized();
|
||||
static auto exec_preset_fast = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::build_mf::exec_presets::Materialized();
|
||||
|
||||
/* This is just a utility function to keep the individual cases smaller. */
|
||||
auto dispatch = [&](auto exec_preset, auto math_function) -> bool {
|
||||
|
@ -341,7 +341,7 @@ inline bool try_dispatch_float_math_fl3_fl3_fl_to_fl3(const NodeVectorMathOperat
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto exec_preset_slow = fn::CustomMF_presets::Materialized();
|
||||
static auto exec_preset_slow = fn::build_mf::exec_presets::Materialized();
|
||||
|
||||
/* This is just a utility function to keep the individual cases smaller. */
|
||||
auto dispatch = [&](auto exec_preset, auto math_function) -> bool {
|
||||
|
@ -373,7 +373,7 @@ inline bool try_dispatch_float_math_fl3_to_fl(const NodeVectorMathOperation oper
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto exec_preset_fast = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_fast = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
|
||||
/* This is just a utility function to keep the individual cases smaller. */
|
||||
auto dispatch = [&](auto exec_preset, auto math_function) -> bool {
|
||||
|
@ -402,7 +402,7 @@ inline bool try_dispatch_float_math_fl3_fl_to_fl3(const NodeVectorMathOperation
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto exec_preset_fast = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_fast = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
|
||||
/* This is just a utility function to keep the individual cases smaller. */
|
||||
auto dispatch = [&](auto exec_preset, auto math_function) -> bool {
|
||||
|
@ -433,8 +433,8 @@ inline bool try_dispatch_float_math_fl3_to_fl3(const NodeVectorMathOperation ope
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto exec_preset_fast = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::CustomMF_presets::Materialized();
|
||||
static auto exec_preset_fast = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_slow = fn::build_mf::exec_presets::Materialized();
|
||||
|
||||
/* This is just a utility function to keep the individual cases smaller. */
|
||||
auto dispatch = [&](auto exec_preset, auto math_function) -> bool {
|
||||
|
|
|
@ -67,24 +67,25 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
|
|||
|
||||
static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
||||
{
|
||||
static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static fn::CustomMF_SI_SI_SO<bool, bool, bool> and_fn{
|
||||
"And", [](bool a, bool b) { return a && b; }, exec_preset};
|
||||
static fn::CustomMF_SI_SI_SO<bool, bool, bool> or_fn{
|
||||
"Or", [](bool a, bool b) { return a || b; }, exec_preset};
|
||||
static fn::CustomMF_SI_SO<bool, bool> not_fn{"Not", [](bool a) { return !a; }, exec_preset};
|
||||
static fn::CustomMF_SI_SI_SO<bool, bool, bool> nand_fn{
|
||||
"Not And", [](bool a, bool b) { return !(a && b); }, exec_preset};
|
||||
static fn::CustomMF_SI_SI_SO<bool, bool, bool> nor_fn{
|
||||
"Nor", [](bool a, bool b) { return !(a || b); }, exec_preset};
|
||||
static fn::CustomMF_SI_SI_SO<bool, bool, bool> xnor_fn{
|
||||
"Equal", [](bool a, bool b) { return a == b; }, exec_preset};
|
||||
static fn::CustomMF_SI_SI_SO<bool, bool, bool> xor_fn{
|
||||
"Not Equal", [](bool a, bool b) { return a != b; }, exec_preset};
|
||||
static fn::CustomMF_SI_SI_SO<bool, bool, bool> imply_fn{
|
||||
"Imply", [](bool a, bool b) { return !a || b; }, exec_preset};
|
||||
static fn::CustomMF_SI_SI_SO<bool, bool, bool> nimply_fn{
|
||||
"Subtract", [](bool a, bool b) { return a && !b; }, exec_preset};
|
||||
static auto exec_preset = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
static auto and_fn = fn::build_mf::SI2_SO<bool, bool, bool>(
|
||||
"And", [](bool a, bool b) { return a && b; }, exec_preset);
|
||||
static auto or_fn = fn::build_mf::SI2_SO<bool, bool, bool>(
|
||||
"Or", [](bool a, bool b) { return a || b; }, exec_preset);
|
||||
static auto not_fn = fn::build_mf::SI1_SO<bool, bool>(
|
||||
"Not", [](bool a) { return !a; }, exec_preset);
|
||||
static auto nand_fn = fn::build_mf::SI2_SO<bool, bool, bool>(
|
||||
"Not And", [](bool a, bool b) { return !(a && b); }, exec_preset);
|
||||
static auto nor_fn = fn::build_mf::SI2_SO<bool, bool, bool>(
|
||||
"Nor", [](bool a, bool b) { return !(a || b); }, exec_preset);
|
||||
static auto xnor_fn = fn::build_mf::SI2_SO<bool, bool, bool>(
|
||||
"Equal", [](bool a, bool b) { return a == b; }, exec_preset);
|
||||
static auto xor_fn = fn::build_mf::SI2_SO<bool, bool, bool>(
|
||||
"Not Equal", [](bool a, bool b) { return a != b; }, exec_preset);
|
||||
static auto imply_fn = fn::build_mf::SI2_SO<bool, bool, bool>(
|
||||
"Imply", [](bool a, bool b) { return !a || b; }, exec_preset);
|
||||
static auto nimply_fn = fn::build_mf::SI2_SO<bool, bool, bool>(
|
||||
"Subtract", [](bool a, bool b) { return a && !b; }, exec_preset);
|
||||
|
||||
switch (bnode.custom1) {
|
||||
case NODE_BOOLEAN_MATH_AND:
|
||||
|
|
|
@ -53,22 +53,22 @@ static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
|||
{
|
||||
const NodeCombSepColor &storage = node_storage(bnode);
|
||||
|
||||
static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> rgba_fn{
|
||||
"RGB", [](float r, float g, float b, float a) { return ColorGeometry4f(r, g, b, a); }};
|
||||
static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> hsva_fn{
|
||||
static auto rgba_fn = fn::build_mf::SI4_SO<float, float, float, float, ColorGeometry4f>(
|
||||
"RGB", [](float r, float g, float b, float a) { return ColorGeometry4f(r, g, b, a); });
|
||||
static auto hsva_fn = fn::build_mf::SI4_SO<float, float, float, float, ColorGeometry4f>(
|
||||
"HSV", [](float h, float s, float v, float a) {
|
||||
ColorGeometry4f r_color;
|
||||
hsv_to_rgb(h, s, v, &r_color.r, &r_color.g, &r_color.b);
|
||||
r_color.a = a;
|
||||
return r_color;
|
||||
}};
|
||||
static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> hsla_fn{
|
||||
});
|
||||
static auto hsla_fn = fn::build_mf::SI4_SO<float, float, float, float, ColorGeometry4f>(
|
||||
"HSL", [](float h, float s, float l, float a) {
|
||||
ColorGeometry4f color;
|
||||
hsl_to_rgb(h, s, l, &color.r, &color.g, &color.b);
|
||||
color.a = a;
|
||||
return color;
|
||||
}};
|
||||
});
|
||||
|
||||
switch (storage.mode) {
|
||||
case NODE_COMBSEP_COLOR_RGB:
|
||||
|
|
|
@ -168,77 +168,77 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
{
|
||||
const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage;
|
||||
|
||||
static auto exec_preset_all = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_first_two = fn::CustomMF_presets::SomeSpanOrSingle<0, 1>();
|
||||
static auto exec_preset_all = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
static auto exec_preset_first_two = fn::build_mf::exec_presets::SomeSpanOrSingle<0, 1>();
|
||||
|
||||
switch (data->data_type) {
|
||||
case SOCK_FLOAT:
|
||||
switch (data->operation) {
|
||||
case NODE_COMPARE_LESS_THAN: {
|
||||
static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
|
||||
"Less Than", [](float a, float b) { return a < b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<float, float, bool>(
|
||||
"Less Than", [](float a, float b) { return a < b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_LESS_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
|
||||
"Less Equal", [](float a, float b) { return a <= b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<float, float, bool>(
|
||||
"Less Equal", [](float a, float b) { return a <= b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_GREATER_THAN: {
|
||||
static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
|
||||
"Greater Than", [](float a, float b) { return a > b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<float, float, bool>(
|
||||
"Greater Than", [](float a, float b) { return a > b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_GREATER_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
|
||||
"Greater Equal", [](float a, float b) { return a >= b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<float, float, bool>(
|
||||
"Greater Equal", [](float a, float b) { return a >= b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float, float, float, bool>(
|
||||
"Equal",
|
||||
[](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_NOT_EQUAL:
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float, float, float, bool>(
|
||||
"Not Equal",
|
||||
[](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
break;
|
||||
case SOCK_INT:
|
||||
switch (data->operation) {
|
||||
case NODE_COMPARE_LESS_THAN: {
|
||||
static fn::CustomMF_SI_SI_SO<int, int, bool> fn{
|
||||
"Less Than", [](int a, int b) { return a < b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<int, int, bool>(
|
||||
"Less Than", [](int a, int b) { return a < b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_LESS_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SO<int, int, bool> fn{
|
||||
"Less Equal", [](int a, int b) { return a <= b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<int, int, bool>(
|
||||
"Less Equal", [](int a, int b) { return a <= b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_GREATER_THAN: {
|
||||
static fn::CustomMF_SI_SI_SO<int, int, bool> fn{
|
||||
"Greater Than", [](int a, int b) { return a > b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<int, int, bool>(
|
||||
"Greater Than", [](int a, int b) { return a > b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_GREATER_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SO<int, int, bool> fn{
|
||||
"Greater Equal", [](int a, int b) { return a >= b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<int, int, bool>(
|
||||
"Greater Equal", [](int a, int b) { return a >= b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SO<int, int, bool> fn{
|
||||
"Equal", [](int a, int b) { return a == b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<int, int, bool>(
|
||||
"Equal", [](int a, int b) { return a == b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_NOT_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SO<int, int, bool> fn{
|
||||
"Not Equal", [](int a, int b) { return a != b; }, exec_preset_all};
|
||||
static auto fn = fn::build_mf::SI2_SO<int, int, bool>(
|
||||
"Not Equal", [](int a, int b) { return a != b; }, exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
@ -248,38 +248,38 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
case NODE_COMPARE_LESS_THAN:
|
||||
switch (data->mode) {
|
||||
case NODE_COMPARE_MODE_AVERAGE: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Less Than - Average",
|
||||
[](float3 a, float3 b) { return component_average(a) < component_average(b); },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DOT_PRODUCT: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Less Than - Dot Product",
|
||||
[](float3 a, float3 b, float comp) { return math::dot(a, b) < comp; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DIRECTION: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Less Than - Direction",
|
||||
[](float3 a, float3 b, float angle) { return angle_v3v3(a, b) < angle; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_ELEMENT: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Less Than - Element-wise",
|
||||
[](float3 a, float3 b) { return a.x < b.x && a.y < b.y && a.z < b.z; },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_LENGTH: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Less Than - Length",
|
||||
[](float3 a, float3 b) { return math::length(a) < math::length(b); },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
@ -287,38 +287,38 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
case NODE_COMPARE_LESS_EQUAL:
|
||||
switch (data->mode) {
|
||||
case NODE_COMPARE_MODE_AVERAGE: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Less Equal - Average",
|
||||
[](float3 a, float3 b) { return component_average(a) <= component_average(b); },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DOT_PRODUCT: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Less Equal - Dot Product",
|
||||
[](float3 a, float3 b, float comp) { return math::dot(a, b) <= comp; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DIRECTION: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Less Equal - Direction",
|
||||
[](float3 a, float3 b, float angle) { return angle_v3v3(a, b) <= angle; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_ELEMENT: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Less Equal - Element-wise",
|
||||
[](float3 a, float3 b) { return a.x <= b.x && a.y <= b.y && a.z <= b.z; },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_LENGTH: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Less Equal - Length",
|
||||
[](float3 a, float3 b) { return math::length(a) <= math::length(b); },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
@ -326,38 +326,38 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
case NODE_COMPARE_GREATER_THAN:
|
||||
switch (data->mode) {
|
||||
case NODE_COMPARE_MODE_AVERAGE: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Greater Than - Average",
|
||||
[](float3 a, float3 b) { return component_average(a) > component_average(b); },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DOT_PRODUCT: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Greater Than - Dot Product",
|
||||
[](float3 a, float3 b, float comp) { return math::dot(a, b) > comp; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DIRECTION: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Greater Than - Direction",
|
||||
[](float3 a, float3 b, float angle) { return angle_v3v3(a, b) > angle; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_ELEMENT: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Greater Than - Element-wise",
|
||||
[](float3 a, float3 b) { return a.x > b.x && a.y > b.y && a.z > b.z; },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_LENGTH: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Greater Than - Length",
|
||||
[](float3 a, float3 b) { return math::length(a) > math::length(b); },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
@ -365,38 +365,38 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
case NODE_COMPARE_GREATER_EQUAL:
|
||||
switch (data->mode) {
|
||||
case NODE_COMPARE_MODE_AVERAGE: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Greater Equal - Average",
|
||||
[](float3 a, float3 b) { return component_average(a) >= component_average(b); },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DOT_PRODUCT: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Greater Equal - Dot Product",
|
||||
[](float3 a, float3 b, float comp) { return math::dot(a, b) >= comp; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DIRECTION: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Greater Equal - Direction",
|
||||
[](float3 a, float3 b, float angle) { return angle_v3v3(a, b) >= angle; },
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_ELEMENT: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Greater Equal - Element-wise",
|
||||
[](float3 a, float3 b) { return a.x >= b.x && a.y >= b.y && a.z >= b.z; },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_LENGTH: {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, bool>(
|
||||
"Greater Equal - Length",
|
||||
[](float3 a, float3 b) { return math::length(a) >= math::length(b); },
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
@ -404,49 +404,49 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
case NODE_COMPARE_EQUAL:
|
||||
switch (data->mode) {
|
||||
case NODE_COMPARE_MODE_AVERAGE: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Equal - Average",
|
||||
[](float3 a, float3 b, float epsilon) {
|
||||
return abs(component_average(a) - component_average(b)) <= epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DOT_PRODUCT: {
|
||||
static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI4_SO<float3, float3, float, float, bool>(
|
||||
"Equal - Dot Product",
|
||||
[](float3 a, float3 b, float comp, float epsilon) {
|
||||
return abs(math::dot(a, b) - comp) <= epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DIRECTION: {
|
||||
static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI4_SO<float3, float3, float, float, bool>(
|
||||
"Equal - Direction",
|
||||
[](float3 a, float3 b, float angle, float epsilon) {
|
||||
return abs(angle_v3v3(a, b) - angle) <= epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_ELEMENT: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Equal - Element-wise",
|
||||
[](float3 a, float3 b, float epsilon) {
|
||||
return abs(a.x - b.x) <= epsilon && abs(a.y - b.y) <= epsilon &&
|
||||
abs(a.z - b.z) <= epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_LENGTH: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Equal - Length",
|
||||
[](float3 a, float3 b, float epsilon) {
|
||||
return abs(math::length(a) - math::length(b)) <= epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
@ -454,49 +454,49 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
case NODE_COMPARE_NOT_EQUAL:
|
||||
switch (data->mode) {
|
||||
case NODE_COMPARE_MODE_AVERAGE: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Not Equal - Average",
|
||||
[](float3 a, float3 b, float epsilon) {
|
||||
return abs(component_average(a) - component_average(b)) > epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DOT_PRODUCT: {
|
||||
static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI4_SO<float3, float3, float, float, bool>(
|
||||
"Not Equal - Dot Product",
|
||||
[](float3 a, float3 b, float comp, float epsilon) {
|
||||
return abs(math::dot(a, b) - comp) >= epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_DIRECTION: {
|
||||
static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI4_SO<float3, float3, float, float, bool>(
|
||||
"Not Equal - Direction",
|
||||
[](float3 a, float3 b, float angle, float epsilon) {
|
||||
return abs(angle_v3v3(a, b) - angle) > epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_ELEMENT: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Not Equal - Element-wise",
|
||||
[](float3 a, float3 b, float epsilon) {
|
||||
return abs(a.x - b.x) > epsilon || abs(a.y - b.y) > epsilon ||
|
||||
abs(a.z - b.z) > epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_MODE_LENGTH: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, bool>(
|
||||
"Not Equal - Length",
|
||||
[](float3 a, float3 b, float epsilon) {
|
||||
return abs(math::length(a) - math::length(b)) > epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
@ -506,41 +506,41 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
case SOCK_RGBA:
|
||||
switch (data->operation) {
|
||||
case NODE_COMPARE_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<ColorGeometry4f, ColorGeometry4f, float, bool>(
|
||||
"Equal",
|
||||
[](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
|
||||
return abs(a.r - b.r) <= epsilon && abs(a.g - b.g) <= epsilon &&
|
||||
abs(a.b - b.b) <= epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_NOT_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<ColorGeometry4f, ColorGeometry4f, float, bool>(
|
||||
"Not Equal",
|
||||
[](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
|
||||
return abs(a.r - b.r) > epsilon || abs(a.g - b.g) > epsilon ||
|
||||
abs(a.b - b.b) > epsilon;
|
||||
},
|
||||
exec_preset_first_two};
|
||||
exec_preset_first_two);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_COLOR_BRIGHTER: {
|
||||
static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<ColorGeometry4f, ColorGeometry4f, bool>(
|
||||
"Brighter",
|
||||
[](ColorGeometry4f a, ColorGeometry4f b) {
|
||||
return rgb_to_grayscale(a) > rgb_to_grayscale(b);
|
||||
},
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_COLOR_DARKER: {
|
||||
static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{
|
||||
static auto fn = fn::build_mf::SI2_SO<ColorGeometry4f, ColorGeometry4f, bool>(
|
||||
"Darker",
|
||||
[](ColorGeometry4f a, ColorGeometry4f b) {
|
||||
return rgb_to_grayscale(a) < rgb_to_grayscale(b);
|
||||
},
|
||||
exec_preset_all};
|
||||
exec_preset_all);
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
@ -548,13 +548,13 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
case SOCK_STRING:
|
||||
switch (data->operation) {
|
||||
case NODE_COMPARE_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{
|
||||
"Equal", [](std::string a, std::string b) { return a == b; }};
|
||||
static auto fn = fn::build_mf::SI2_SO<std::string, std::string, bool>(
|
||||
"Equal", [](std::string a, std::string b) { return a == b; });
|
||||
return &fn;
|
||||
}
|
||||
case NODE_COMPARE_NOT_EQUAL: {
|
||||
static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{
|
||||
"Not Equal", [](std::string a, std::string b) { return a != b; }};
|
||||
static auto fn = fn::build_mf::SI2_SO<std::string, std::string, bool>(
|
||||
"Not Equal", [](std::string a, std::string b) { return a != b; });
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,15 +38,15 @@ static void node_label(const bNodeTree * /*tree*/, const bNode *node, char *labe
|
|||
|
||||
static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
||||
{
|
||||
static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle();
|
||||
static fn::CustomMF_SI_SO<float, int> round_fn{
|
||||
"Round", [](float a) { return int(round(a)); }, exec_preset};
|
||||
static fn::CustomMF_SI_SO<float, int> floor_fn{
|
||||
"Floor", [](float a) { return int(floor(a)); }, exec_preset};
|
||||
static fn::CustomMF_SI_SO<float, int> ceil_fn{
|
||||
"Ceiling", [](float a) { return int(ceil(a)); }, exec_preset};
|
||||
static fn::CustomMF_SI_SO<float, int> trunc_fn{
|
||||
"Truncate", [](float a) { return int(trunc(a)); }, exec_preset};
|
||||
static auto exec_preset = fn::build_mf::exec_presets::AllSpanOrSingle();
|
||||
static auto round_fn = fn::build_mf::SI1_SO<float, int>(
|
||||
"Round", [](float a) { return int(round(a)); }, exec_preset);
|
||||
static auto floor_fn = fn::build_mf::SI1_SO<float, int>(
|
||||
"Floor", [](float a) { return int(floor(a)); }, exec_preset);
|
||||
static auto ceil_fn = fn::build_mf::SI1_SO<float, int>(
|
||||
"Ceiling", [](float a) { return int(ceil(a)); }, exec_preset);
|
||||
static auto trunc_fn = fn::build_mf::SI1_SO<float, int>(
|
||||
"Truncate", [](float a) { return int(trunc(a)); }, exec_preset);
|
||||
|
||||
switch (static_cast<FloatToIntRoundingMode>(bnode.custom1)) {
|
||||
case FN_NODE_FLOAT_TO_INT_ROUND:
|
||||
|
|
|
@ -141,64 +141,49 @@ static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
|
|||
|
||||
switch (data_type) {
|
||||
case CD_PROP_FLOAT3: {
|
||||
static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float3>>
|
||||
fn{"Random Vector",
|
||||
[](float3 min_value, float3 max_value, int id, int seed, float3 *r_value) {
|
||||
const float x = noise::hash_to_float(seed, id, 0);
|
||||
const float y = noise::hash_to_float(seed, id, 1);
|
||||
const float z = noise::hash_to_float(seed, id, 2);
|
||||
*r_value = float3(x, y, z) * (max_value - min_value) + min_value;
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<2>()};
|
||||
static auto fn = fn::build_mf::SI4_SO<float3, float3, int, int, float3>(
|
||||
"Random Vector",
|
||||
[](float3 min_value, float3 max_value, int id, int seed) -> float3 {
|
||||
const float x = noise::hash_to_float(seed, id, 0);
|
||||
const float y = noise::hash_to_float(seed, id, 1);
|
||||
const float z = noise::hash_to_float(seed, id, 2);
|
||||
return float3(x, y, z) * (max_value - min_value) + min_value;
|
||||
},
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<2>());
|
||||
builder.set_matching_fn(fn);
|
||||
break;
|
||||
}
|
||||
case CD_PROP_FLOAT: {
|
||||
static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float>>
|
||||
fn{"Random Float",
|
||||
[](float min_value, float max_value, int id, int seed, float *r_value) {
|
||||
const float value = noise::hash_to_float(seed, id);
|
||||
*r_value = value * (max_value - min_value) + min_value;
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<2>()};
|
||||
static auto fn = fn::build_mf::SI4_SO<float, float, int, int, float>(
|
||||
"Random Float",
|
||||
[](float min_value, float max_value, int id, int seed) -> float {
|
||||
const float value = noise::hash_to_float(seed, id);
|
||||
return value * (max_value - min_value) + min_value;
|
||||
},
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<2>());
|
||||
builder.set_matching_fn(fn);
|
||||
break;
|
||||
}
|
||||
case CD_PROP_INT32: {
|
||||
static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, int>>
|
||||
fn{"Random Int",
|
||||
[](int min_value, int max_value, int id, int seed, int *r_value) {
|
||||
const float value = noise::hash_to_float(id, seed);
|
||||
/* Add one to the maximum and use floor to produce an even
|
||||
* distribution for the first and last values (See T93591). */
|
||||
*r_value = floor(value * (max_value + 1 - min_value) + min_value);
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<2>()};
|
||||
static auto fn = fn::build_mf::SI4_SO<int, int, int, int, int>(
|
||||
"Random Int",
|
||||
[](int min_value, int max_value, int id, int seed) -> int {
|
||||
const float value = noise::hash_to_float(id, seed);
|
||||
/* Add one to the maximum and use floor to produce an even
|
||||
* distribution for the first and last values (See T93591). */
|
||||
return floor(value * (max_value + 1 - min_value) + min_value);
|
||||
},
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<2>());
|
||||
builder.set_matching_fn(fn);
|
||||
break;
|
||||
}
|
||||
case CD_PROP_BOOL: {
|
||||
static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, int>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, bool>>
|
||||
fn{"Random Bool",
|
||||
[](float probability, int id, int seed, bool *r_value) {
|
||||
*r_value = noise::hash_to_float(id, seed) <= probability;
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<1>()};
|
||||
static auto fn = fn::build_mf::SI3_SO<float, int, int, bool>(
|
||||
"Random Bool",
|
||||
[](float probability, int id, int seed) -> bool {
|
||||
return noise::hash_to_float(id, seed) <= probability;
|
||||
},
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<1>());
|
||||
builder.set_matching_fn(fn);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -30,10 +30,12 @@ static std::string replace_all(const StringRefNull str,
|
|||
|
||||
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||
{
|
||||
static fn::CustomMF_SI_SI_SI_SO<std::string, std::string, std::string, std::string> substring_fn{
|
||||
"Replace", [](const std::string &str, const std::string &find, const std::string &replace) {
|
||||
return replace_all(str, find, replace);
|
||||
}};
|
||||
static auto substring_fn =
|
||||
fn::build_mf::SI3_SO<std::string, std::string, std::string, std::string>(
|
||||
"Replace",
|
||||
[](const std::string &str, const std::string &find, const std::string &replace) {
|
||||
return replace_all(str, find, replace);
|
||||
});
|
||||
builder.set_matching_fn(&substring_fn);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
|||
|
||||
static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
||||
{
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, float3> obj_euler_rot{
|
||||
static auto obj_euler_rot = fn::build_mf::SI2_SO<float3, float3, float3>(
|
||||
"Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) {
|
||||
float input_mat[3][3];
|
||||
eul_to_mat3(input_mat, input);
|
||||
|
@ -65,8 +65,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
|||
float3 result;
|
||||
mat3_to_eul(result, mat_res);
|
||||
return result;
|
||||
}};
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> obj_AA_rot{
|
||||
});
|
||||
static auto obj_AA_rot = fn::build_mf::SI3_SO<float3, float3, float, float3>(
|
||||
"Rotate Euler by AxisAngle/Object",
|
||||
[](const float3 &input, const float3 &axis, float angle) {
|
||||
float input_mat[3][3];
|
||||
|
@ -78,8 +78,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
|||
float3 result;
|
||||
mat3_to_eul(result, mat_res);
|
||||
return result;
|
||||
}};
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, float3> local_euler_rot{
|
||||
});
|
||||
static auto local_euler_rot = fn::build_mf::SI2_SO<float3, float3, float3>(
|
||||
"Rotate Euler by Euler/Local", [](const float3 &input, const float3 &rotation) {
|
||||
float input_mat[3][3];
|
||||
eul_to_mat3(input_mat, input);
|
||||
|
@ -90,8 +90,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
|||
float3 result;
|
||||
mat3_to_eul(result, mat_res);
|
||||
return result;
|
||||
}};
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> local_AA_rot{
|
||||
});
|
||||
static auto local_AA_rot = fn::build_mf::SI3_SO<float3, float3, float, float3>(
|
||||
"Rotate Euler by AxisAngle/Local", [](const float3 &input, const float3 &axis, float angle) {
|
||||
float input_mat[3][3];
|
||||
eul_to_mat3(input_mat, input);
|
||||
|
@ -102,14 +102,18 @@ static const fn::MultiFunction *get_multi_function(const bNode &bnode)
|
|||
float3 result;
|
||||
mat3_to_eul(result, mat_res);
|
||||
return result;
|
||||
}};
|
||||
});
|
||||
short type = bnode.custom1;
|
||||
short space = bnode.custom2;
|
||||
if (type == FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE) {
|
||||
return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_AA_rot : &local_AA_rot;
|
||||
return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ?
|
||||
static_cast<const MultiFunction *>(&obj_AA_rot) :
|
||||
&local_AA_rot;
|
||||
}
|
||||
if (type == FN_NODE_ROTATE_EULER_TYPE_EULER) {
|
||||
return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_euler_rot : &local_euler_rot;
|
||||
return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ?
|
||||
static_cast<const MultiFunction *>(&obj_euler_rot) :
|
||||
&local_euler_rot;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
|
|
|
@ -16,13 +16,13 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
|
||||
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||
{
|
||||
static fn::CustomMF_SI_SI_SI_SO<std::string, int, int, std::string> slice_fn{
|
||||
static auto slice_fn = fn::build_mf::SI3_SO<std::string, int, int, std::string>(
|
||||
"Slice", [](const std::string &str, int a, int b) {
|
||||
const int len = BLI_strlen_utf8(str.c_str());
|
||||
const int start = BLI_str_utf8_offset_from_index(str.c_str(), std::clamp(a, 0, len));
|
||||
const int end = BLI_str_utf8_offset_from_index(str.c_str(), std::clamp(a + b, 0, len));
|
||||
return str.substr(start, std::max<int>(end - start, 0));
|
||||
}};
|
||||
});
|
||||
builder.set_matching_fn(&slice_fn);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
|
||||
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||
{
|
||||
static fn::CustomMF_SI_SO<std::string, int> str_len_fn{
|
||||
"String Length", [](const std::string &a) { return BLI_strlen_utf8(a.c_str()); }};
|
||||
static auto str_len_fn = fn::build_mf::SI1_SO<std::string, int>(
|
||||
"String Length", [](const std::string &a) { return BLI_strlen_utf8(a.c_str()); });
|
||||
builder.set_matching_fn(&str_len_fn);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
|
||||
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||
{
|
||||
static fn::CustomMF_SI_SI_SO<float, int, std::string> to_str_fn{
|
||||
static auto to_str_fn = fn::build_mf::SI2_SO<float, int, std::string>(
|
||||
"Value To String", [](float a, int b) {
|
||||
std::stringstream stream;
|
||||
stream << std::fixed << std::setprecision(std::max(0, b)) << a;
|
||||
return stream.str();
|
||||
}};
|
||||
});
|
||||
builder.set_matching_fn(&to_str_fn);
|
||||
}
|
||||
|
||||
|
|
|
@ -1325,10 +1325,10 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
|
||||
/* Create a combined field from the offset and the scale so the field evaluator
|
||||
* can take care of the multiplication and to simplify each extrude function. */
|
||||
static fn::CustomMF_SI_SI_SO<float3, float, float3> multiply_fn{
|
||||
static auto multiply_fn = fn::build_mf::SI2_SO<float3, float, float3>(
|
||||
"Scale",
|
||||
[](const float3 &offset, const float scale) { return offset * scale; },
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
std::shared_ptr<FieldOperation> multiply_op = std::make_shared<FieldOperation>(
|
||||
FieldOperation(multiply_fn, {std::move(offset_field), std::move(scale_field)}));
|
||||
const Field<float3> final_offset{std::move(multiply_op)};
|
||||
|
|
|
@ -121,10 +121,10 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
|
||||
/* Use another multi-function operation to make sure the input radius is greater than zero.
|
||||
* TODO: Use mutable multi-function once that is supported. */
|
||||
static fn::CustomMF_SI_SO<float, float> max_zero_fn(
|
||||
static auto max_zero_fn = fn::build_mf::SI1_SO<float, float>(
|
||||
__func__,
|
||||
[](float value) { return std::max(0.0f, value); },
|
||||
fn::CustomMF_presets::AllSpanOrSingle());
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
auto max_zero_op = std::make_shared<FieldOperation>(
|
||||
FieldOperation(max_zero_fn, {std::move(radius)}));
|
||||
Field<float> positive_radius(std::move(max_zero_op), 0);
|
||||
|
|
|
@ -171,10 +171,10 @@ template<typename T> void switch_fields(GeoNodeExecParams ¶ms, const StringR
|
|||
Field<T> falses_field = params.extract_input<Field<T>>(name_false);
|
||||
Field<T> trues_field = params.extract_input<Field<T>>(name_true);
|
||||
|
||||
static fn::CustomMF_SI_SI_SI_SO<bool, T, T, T> switch_fn{
|
||||
static auto switch_fn = fn::build_mf::SI3_SO<bool, T, T, T>(
|
||||
"Switch", [](bool condition, const T &false_value, const T &true_value) {
|
||||
return condition ? true_value : false_value;
|
||||
}};
|
||||
});
|
||||
|
||||
auto switch_op = std::make_shared<FieldOperation>(FieldOperation(
|
||||
std::move(switch_fn),
|
||||
|
|
|
@ -44,17 +44,17 @@ static int gpu_shader_clamp(GPUMaterial *mat,
|
|||
|
||||
static void sh_node_clamp_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||
{
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> minmax_fn{
|
||||
static auto minmax_fn = fn::build_mf::SI3_SO<float, float, float, float>(
|
||||
"Clamp (Min Max)",
|
||||
[](float value, float min, float max) { return std::min(std::max(value, min), max); }};
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> range_fn{
|
||||
[](float value, float min, float max) { return std::min(std::max(value, min), max); });
|
||||
static auto range_fn = fn::build_mf::SI3_SO<float, float, float, float>(
|
||||
"Clamp (Range)", [](float value, float a, float b) {
|
||||
if (a < b) {
|
||||
return clamp_f(value, a, b);
|
||||
}
|
||||
|
||||
return clamp_f(value, b, a);
|
||||
}};
|
||||
});
|
||||
|
||||
int clamp_type = builder.node().custom1;
|
||||
if (clamp_type == NODE_CLAMP_MINMAX) {
|
||||
|
|
|
@ -233,103 +233,74 @@ static float3 clamp_range(const float3 value, const float3 min, const float3 max
|
|||
|
||||
template<bool Clamp> static auto build_float_linear()
|
||||
{
|
||||
return fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float>>{
|
||||
return fn::build_mf::SI5_SO<float, float, float, float, float, float>(
|
||||
Clamp ? "Map Range (clamped)" : "Map Range (unclamped)",
|
||||
[](float value, float from_min, float from_max, float to_min, float to_max, float *r_value) {
|
||||
[](float value, float from_min, float from_max, float to_min, float to_max) -> float {
|
||||
const float factor = safe_divide(value - from_min, from_max - from_min);
|
||||
float result = to_min + factor * (to_max - to_min);
|
||||
if constexpr (Clamp) {
|
||||
result = clamp_range(result, to_min, to_max);
|
||||
}
|
||||
*r_value = result;
|
||||
return result;
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<0>()};
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<0>());
|
||||
}
|
||||
|
||||
template<bool Clamp> static auto build_float_stepped()
|
||||
{
|
||||
return fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float>>{
|
||||
return fn::build_mf::SI6_SO<float, float, float, float, float, float, float>(
|
||||
Clamp ? "Map Range Stepped (clamped)" : "Map Range Stepped (unclamped)",
|
||||
[](float value,
|
||||
float from_min,
|
||||
float from_max,
|
||||
float to_min,
|
||||
float to_max,
|
||||
float steps,
|
||||
float *r_value) {
|
||||
[](float value, float from_min, float from_max, float to_min, float to_max, float steps)
|
||||
-> float {
|
||||
float factor = safe_divide(value - from_min, from_max - from_min);
|
||||
factor = safe_divide(floorf(factor * (steps + 1.0f)), steps);
|
||||
float result = to_min + factor * (to_max - to_min);
|
||||
if constexpr (Clamp) {
|
||||
result = clamp_range(result, to_min, to_max);
|
||||
}
|
||||
*r_value = result;
|
||||
return result;
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<0>()};
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<0>());
|
||||
}
|
||||
|
||||
template<bool Clamp> static auto build_vector_linear()
|
||||
{
|
||||
return fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float3>>{
|
||||
return fn::build_mf::SI5_SO<float3, float3, float3, float3, float3, float3>(
|
||||
Clamp ? "Vector Map Range (clamped)" : "Vector Map Range (unclamped)",
|
||||
[](const float3 &value,
|
||||
const float3 &from_min,
|
||||
const float3 &from_max,
|
||||
const float3 &to_min,
|
||||
const float3 &to_max,
|
||||
float3 *r_value) {
|
||||
const float3 &to_max) -> float3 {
|
||||
float3 factor = math::safe_divide(value - from_min, from_max - from_min);
|
||||
float3 result = factor * (to_max - to_min) + to_min;
|
||||
if constexpr (Clamp) {
|
||||
result = clamp_range(result, to_min, to_max);
|
||||
}
|
||||
*r_value = result;
|
||||
return result;
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<0>()};
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<0>());
|
||||
}
|
||||
|
||||
template<bool Clamp> static auto build_vector_stepped()
|
||||
{
|
||||
return fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float3>>{
|
||||
return fn::build_mf::SI6_SO<float3, float3, float3, float3, float3, float3, float3>(
|
||||
Clamp ? "Vector Map Range Stepped (clamped)" : "Vector Map Range Stepped (unclamped)",
|
||||
[](const float3 &value,
|
||||
const float3 &from_min,
|
||||
const float3 &from_max,
|
||||
const float3 &to_min,
|
||||
const float3 &to_max,
|
||||
const float3 &steps,
|
||||
float3 *r_value) {
|
||||
const float3 &steps) -> float3 {
|
||||
float3 factor = math::safe_divide(value - from_min, from_max - from_min);
|
||||
factor = math::safe_divide(math::floor(factor * (steps + 1.0f)), steps);
|
||||
float3 result = factor * (to_max - to_min) + to_min;
|
||||
if constexpr (Clamp) {
|
||||
result = clamp_range(result, to_min, to_max);
|
||||
}
|
||||
*r_value = result;
|
||||
return result;
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<0>()};
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<0>());
|
||||
}
|
||||
|
||||
static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||
|
@ -364,48 +335,36 @@ static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &bui
|
|||
break;
|
||||
}
|
||||
case NODE_MAP_RANGE_SMOOTHSTEP: {
|
||||
static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float3>>
|
||||
fn{"Vector Map Range Smoothstep",
|
||||
[](const float3 &value,
|
||||
const float3 &from_min,
|
||||
const float3 &from_max,
|
||||
const float3 &to_min,
|
||||
const float3 &to_max,
|
||||
float3 *r_value) {
|
||||
float3 factor = math::safe_divide(value - from_min, from_max - from_min);
|
||||
clamp_v3(factor, 0.0f, 1.0f);
|
||||
factor = (float3(3.0f) - 2.0f * factor) * (factor * factor);
|
||||
*r_value = factor * (to_max - to_min) + to_min;
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<0>()};
|
||||
static auto fn = fn::build_mf::SI5_SO<float3, float3, float3, float3, float3, float3>(
|
||||
"Vector Map Range Smoothstep",
|
||||
[](const float3 &value,
|
||||
const float3 &from_min,
|
||||
const float3 &from_max,
|
||||
const float3 &to_min,
|
||||
const float3 &to_max) -> float3 {
|
||||
float3 factor = math::safe_divide(value - from_min, from_max - from_min);
|
||||
clamp_v3(factor, 0.0f, 1.0f);
|
||||
factor = (float3(3.0f) - 2.0f * factor) * (factor * factor);
|
||||
return factor * (to_max - to_min) + to_min;
|
||||
},
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<0>());
|
||||
builder.set_matching_fn(fn);
|
||||
break;
|
||||
}
|
||||
case NODE_MAP_RANGE_SMOOTHERSTEP: {
|
||||
static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float3>>
|
||||
fn{"Vector Map Range Smootherstep",
|
||||
[](const float3 &value,
|
||||
const float3 &from_min,
|
||||
const float3 &from_max,
|
||||
const float3 &to_min,
|
||||
const float3 &to_max,
|
||||
float3 *r_value) {
|
||||
float3 factor = math::safe_divide(value - from_min, from_max - from_min);
|
||||
clamp_v3(factor, 0.0f, 1.0f);
|
||||
factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
|
||||
*r_value = factor * (to_max - to_min) + to_min;
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<0>()};
|
||||
static auto fn = fn::build_mf::SI5_SO<float3, float3, float3, float3, float3, float3>(
|
||||
"Vector Map Range Smootherstep",
|
||||
[](const float3 &value,
|
||||
const float3 &from_min,
|
||||
const float3 &from_max,
|
||||
const float3 &to_min,
|
||||
const float3 &to_max) -> float3 {
|
||||
float3 factor = math::safe_divide(value - from_min, from_max - from_min);
|
||||
clamp_v3(factor, 0.0f, 1.0f);
|
||||
factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
|
||||
return factor * (to_max - to_min) + to_min;
|
||||
},
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<0>());
|
||||
builder.set_matching_fn(fn);
|
||||
break;
|
||||
}
|
||||
|
@ -438,48 +397,30 @@ static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &bui
|
|||
break;
|
||||
}
|
||||
case NODE_MAP_RANGE_SMOOTHSTEP: {
|
||||
static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float>>
|
||||
fn{"Map Range Smoothstep",
|
||||
[](float value,
|
||||
float from_min,
|
||||
float from_max,
|
||||
float to_min,
|
||||
float to_max,
|
||||
float *r_value) {
|
||||
float factor = safe_divide(value - from_min, from_max - from_min);
|
||||
factor = std::clamp(factor, 0.0f, 1.0f);
|
||||
factor = (3.0f - 2.0f * factor) * (factor * factor);
|
||||
*r_value = to_min + factor * (to_max - to_min);
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<0>()};
|
||||
static auto fn = fn::build_mf::SI5_SO<float, float, float, float, float, float>(
|
||||
"Map Range Smoothstep",
|
||||
[](float value, float from_min, float from_max, float to_min, float to_max)
|
||||
-> float {
|
||||
float factor = safe_divide(value - from_min, from_max - from_min);
|
||||
factor = std::clamp(factor, 0.0f, 1.0f);
|
||||
factor = (3.0f - 2.0f * factor) * (factor * factor);
|
||||
return to_min + factor * (to_max - to_min);
|
||||
},
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<0>());
|
||||
builder.set_matching_fn(fn);
|
||||
break;
|
||||
}
|
||||
case NODE_MAP_RANGE_SMOOTHERSTEP: {
|
||||
static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleInput, float>,
|
||||
fn::MFParamTag<fn::MFParamCategory::SingleOutput, float>>
|
||||
fn{"Map Range Smoothstep",
|
||||
[](float value,
|
||||
float from_min,
|
||||
float from_max,
|
||||
float to_min,
|
||||
float to_max,
|
||||
float *r_value) {
|
||||
float factor = safe_divide(value - from_min, from_max - from_min);
|
||||
factor = std::clamp(factor, 0.0f, 1.0f);
|
||||
factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
|
||||
*r_value = to_min + factor * (to_max - to_min);
|
||||
},
|
||||
fn::CustomMF_presets::SomeSpanOrSingle<0>()};
|
||||
static auto fn = fn::build_mf::SI5_SO<float, float, float, float, float, float>(
|
||||
"Map Range Smoothstep",
|
||||
[](float value, float from_min, float from_max, float to_min, float to_max)
|
||||
-> float {
|
||||
float factor = safe_divide(value - from_min, from_max - from_min);
|
||||
factor = std::clamp(factor, 0.0f, 1.0f);
|
||||
factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
|
||||
return to_min + factor * (to_max - to_min);
|
||||
},
|
||||
fn::build_mf::exec_presets::SomeSpanOrSingle<0>());
|
||||
builder.set_matching_fn(fn);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -109,8 +109,8 @@ static const fn::MultiFunction *get_base_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl_to_fl(
|
||||
mode, [&](auto devi_fn, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SO<float, float> fn{
|
||||
info.title_case_name.c_str(), function, devi_fn};
|
||||
static auto fn = fn::build_mf::SI1_SO<float, float>(
|
||||
info.title_case_name.c_str(), function, devi_fn);
|
||||
base_fn = &fn;
|
||||
});
|
||||
if (base_fn != nullptr) {
|
||||
|
@ -119,8 +119,8 @@ static const fn::MultiFunction *get_base_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl_fl_to_fl(
|
||||
mode, [&](auto devi_fn, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SI_SO<float, float, float> fn{
|
||||
info.title_case_name.c_str(), function, devi_fn};
|
||||
static auto fn = fn::build_mf::SI2_SO<float, float, float>(
|
||||
info.title_case_name.c_str(), function, devi_fn);
|
||||
base_fn = &fn;
|
||||
});
|
||||
if (base_fn != nullptr) {
|
||||
|
@ -129,8 +129,8 @@ static const fn::MultiFunction *get_base_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl_fl_fl_to_fl(
|
||||
mode, [&](auto devi_fn, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{
|
||||
info.title_case_name.c_str(), function, devi_fn};
|
||||
static auto fn = fn::build_mf::SI3_SO<float, float, float, float>(
|
||||
info.title_case_name.c_str(), function, devi_fn);
|
||||
base_fn = &fn;
|
||||
});
|
||||
if (base_fn != nullptr) {
|
||||
|
|
|
@ -412,51 +412,51 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
switch (data->data_type) {
|
||||
case SOCK_FLOAT: {
|
||||
if (clamp_factor) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float, float, float, float>(
|
||||
"Clamp Mix Float", [](float t, const float a, const float b) {
|
||||
return math::interpolate(a, b, std::clamp(t, 0.0f, 1.0f));
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
else {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float, float, float, float>(
|
||||
"Mix Float", [](const float t, const float a, const float b) {
|
||||
return math::interpolate(a, b, t);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
case SOCK_VECTOR: {
|
||||
if (clamp_factor) {
|
||||
if (uniform_factor) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float3, float3, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float, float3, float3, float3>(
|
||||
"Clamp Mix Vector", [](const float t, const float3 a, const float3 b) {
|
||||
return math::interpolate(a, b, std::clamp(t, 0.0f, 1.0f));
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
else {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float3, float3>(
|
||||
"Clamp Mix Vector Non Uniform", [](float3 t, const float3 a, const float3 b) {
|
||||
t = math::clamp(t, 0.0f, 1.0f);
|
||||
return a * (float3(1.0f) - t) + b * t;
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uniform_factor) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float3, float3, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float, float3, float3, float3>(
|
||||
"Mix Vector", [](const float t, const float3 a, const float3 b) {
|
||||
return math::interpolate(a, b, t);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
else {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float3, float3>(
|
||||
"Mix Vector Non Uniform", [](const float3 t, const float3 a, const float3 b) {
|
||||
return a * (float3(1.0f) - t) + b * t;
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,8 +108,8 @@ static int gpu_shader_combrgb(GPUMaterial *mat,
|
|||
|
||||
static void sh_node_combrgb_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||
{
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float, float, ColorGeometry4f> fn{
|
||||
"Combine RGB", [](float r, float g, float b) { return ColorGeometry4f(r, g, b, 1.0f); }};
|
||||
static auto fn = fn::build_mf::SI3_SO<float, float, float, ColorGeometry4f>(
|
||||
"Combine RGB", [](float r, float g, float b) { return ColorGeometry4f(r, g, b, 1.0f); });
|
||||
builder.set_matching_fn(fn);
|
||||
}
|
||||
|
||||
|
|
|
@ -125,10 +125,10 @@ static int gpu_shader_combxyz(GPUMaterial *mat,
|
|||
|
||||
static void sh_node_combxyz_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||
{
|
||||
static fn::CustomMF_SI_SI_SI_SO<float, float, float, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float, float, float, float3>(
|
||||
"Combine Vector",
|
||||
[](float x, float y, float z) { return float3(x, y, z); },
|
||||
fn::CustomMF_presets::AllSpanOrSingle()};
|
||||
fn::build_mf::exec_presets::AllSpanOrSingle());
|
||||
builder.set_matching_fn(fn);
|
||||
}
|
||||
|
||||
|
|
|
@ -233,8 +233,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl3_fl3_to_fl3(
|
||||
operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{
|
||||
info.title_case_name.c_str(), function, exec_preset};
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, float3>(
|
||||
info.title_case_name.c_str(), function, exec_preset);
|
||||
multi_fn = &fn;
|
||||
});
|
||||
if (multi_fn != nullptr) {
|
||||
|
@ -243,8 +243,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
|
||||
operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
|
||||
info.title_case_name.c_str(), function, exec_preset};
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float3, float3>(
|
||||
info.title_case_name.c_str(), function, exec_preset);
|
||||
multi_fn = &fn;
|
||||
});
|
||||
if (multi_fn != nullptr) {
|
||||
|
@ -253,8 +253,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl3_fl3_fl_to_fl3(
|
||||
operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
|
||||
info.title_case_name.c_str(), function, exec_preset};
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, float3>(
|
||||
info.title_case_name.c_str(), function, exec_preset);
|
||||
multi_fn = &fn;
|
||||
});
|
||||
if (multi_fn != nullptr) {
|
||||
|
@ -263,8 +263,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl3_fl3_to_fl(
|
||||
operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float3, float> fn{
|
||||
info.title_case_name.c_str(), function, exec_preset};
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float3, float>(
|
||||
info.title_case_name.c_str(), function, exec_preset);
|
||||
multi_fn = &fn;
|
||||
});
|
||||
if (multi_fn != nullptr) {
|
||||
|
@ -273,8 +273,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl3_fl_to_fl3(
|
||||
operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SI_SO<float3, float, float3> fn{
|
||||
info.title_case_name.c_str(), function, exec_preset};
|
||||
static auto fn = fn::build_mf::SI2_SO<float3, float, float3>(
|
||||
info.title_case_name.c_str(), function, exec_preset);
|
||||
multi_fn = &fn;
|
||||
});
|
||||
if (multi_fn != nullptr) {
|
||||
|
@ -283,8 +283,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl3_to_fl3(
|
||||
operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SO<float3, float3> fn{
|
||||
info.title_case_name.c_str(), function, exec_preset};
|
||||
static auto fn = fn::build_mf::SI1_SO<float3, float3>(
|
||||
info.title_case_name.c_str(), function, exec_preset);
|
||||
multi_fn = &fn;
|
||||
});
|
||||
if (multi_fn != nullptr) {
|
||||
|
@ -293,8 +293,8 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
|
||||
try_dispatch_float_math_fl3_to_fl(
|
||||
operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
|
||||
static fn::CustomMF_SI_SO<float3, float> fn{
|
||||
info.title_case_name.c_str(), function, exec_preset};
|
||||
static auto fn = fn::build_mf::SI1_SO<float3, float>(
|
||||
info.title_case_name.c_str(), function, exec_preset);
|
||||
multi_fn = &fn;
|
||||
});
|
||||
if (multi_fn != nullptr) {
|
||||
|
|
|
@ -104,77 +104,77 @@ static const fn::MultiFunction *get_multi_function(const bNode &node)
|
|||
switch (mode) {
|
||||
case NODE_VECTOR_ROTATE_TYPE_AXIS: {
|
||||
if (invert) {
|
||||
static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
|
||||
static auto fn = fn::build_mf::SI4_SO<float3, float3, float3, float, float3>(
|
||||
"Rotate Axis",
|
||||
[](const float3 &in, const float3 ¢er, const float3 &axis, float angle) {
|
||||
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
|
||||
static auto fn = fn::build_mf::SI4_SO<float3, float3, float3, float, float3>(
|
||||
"Rotate Axis",
|
||||
[](const float3 &in, const float3 ¢er, const float3 &axis, float angle) {
|
||||
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
case NODE_VECTOR_ROTATE_TYPE_AXIS_X: {
|
||||
float3 axis = float3(1.0f, 0.0f, 0.0f);
|
||||
if (invert) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, float3>(
|
||||
"Rotate X-Axis", [=](const float3 &in, const float3 ¢er, float angle) {
|
||||
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, float3>(
|
||||
"Rotate X-Axis", [=](const float3 &in, const float3 ¢er, float angle) {
|
||||
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: {
|
||||
float3 axis = float3(0.0f, 1.0f, 0.0f);
|
||||
if (invert) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, float3>(
|
||||
"Rotate Y-Axis", [=](const float3 &in, const float3 ¢er, float angle) {
|
||||
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, float3>(
|
||||
"Rotate Y-Axis", [=](const float3 &in, const float3 ¢er, float angle) {
|
||||
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: {
|
||||
float3 axis = float3(0.0f, 0.0f, 1.0f);
|
||||
if (invert) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, float3>(
|
||||
"Rotate Z-Axis", [=](const float3 &in, const float3 ¢er, float angle) {
|
||||
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float, float3>(
|
||||
"Rotate Z-Axis", [=](const float3 &in, const float3 ¢er, float angle) {
|
||||
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: {
|
||||
if (invert) {
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float3, float3>(
|
||||
"Rotate Euler", [](const float3 &in, const float3 ¢er, const float3 &rotation) {
|
||||
return sh_node_vector_rotate_euler(in, center, rotation, true);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
|
||||
static auto fn = fn::build_mf::SI3_SO<float3, float3, float3, float3>(
|
||||
"Rotate Euler", [](const float3 &in, const float3 ¢er, const float3 &rotation) {
|
||||
return sh_node_vector_rotate_euler(in, center, rotation, false);
|
||||
}};
|
||||
});
|
||||
return &fn;
|
||||
}
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue