Blender V5.0
list_function_eval.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
10
11namespace blender::nodes {
12
14 public:
15 ListFieldContext() = default;
16
18 const IndexMask &mask,
19 ResourceScope & /*scope*/) const override
20 {
21 const bke::IDAttributeFieldInput *id_field_input =
22 dynamic_cast<const bke::IDAttributeFieldInput *>(&field_input);
23
24 const fn::IndexFieldInput *index_field_input = dynamic_cast<const fn::IndexFieldInput *>(
25 &field_input);
26
27 if (id_field_input == nullptr && index_field_input == nullptr) {
28 return {};
29 }
30
32 }
33};
34
36{
37 const CPPType &cpp_type = field.cpp_type();
39 GMutableSpan span(cpp_type, array_data.data, count);
40
41 ListFieldContext context{};
42 fn::FieldEvaluator evaluator{context, count};
43 evaluator.add_with_destination(std::move(field), span);
44 evaluator.evaluate();
45
46 return List::create(cpp_type, std::move(array_data), count);
47}
48
49static ListPtr create_repeated_list(ListPtr list, const int64_t dst_size)
50{
51 if (list->size() >= dst_size) {
52 return list;
53 }
54 if (const auto *data = std::get_if<nodes::List::ArrayData>(&list->data())) {
55 const int64_t size = list->size();
56 BLI_assert(size > 0);
57 const CPPType &cpp_type = list->cpp_type();
58 List::ArrayData new_data = List::ArrayData::ForUninitialized(cpp_type, dst_size);
59 const int64_t chunks = dst_size / size;
60 for (const int64_t i : IndexRange(chunks)) {
61 const int64_t offset = cpp_type.size * i * size;
62 cpp_type.copy_construct_n(data->data, POINTER_OFFSET(new_data.data, offset), size);
63 }
64 const int64_t last_chunk_size = dst_size % size;
65 if (last_chunk_size > 0) {
66 const int64_t offset = cpp_type.size * chunks * size;
67 cpp_type.copy_construct_n(
68 data->data, POINTER_OFFSET(new_data.data, offset), last_chunk_size);
69 }
70
71 return List::create(cpp_type, std::move(new_data), dst_size);
72 }
73 if (const auto *data = std::get_if<nodes::List::SingleData>(&list->data())) {
74 const CPPType &cpp_type = list->cpp_type();
75 return List::create(cpp_type, *data, dst_size);
76 }
78 return {};
79}
80
81static void add_list_to_params(mf::ParamsBuilder &params,
82 const mf::ParamType &param_type,
83 const List &list)
84{
85 const CPPType &cpp_type = param_type.data_type().single_type();
86 BLI_assert(cpp_type == list.cpp_type());
87 if (const auto *array_data = std::get_if<nodes::List::ArrayData>(&list.data())) {
88 params.add_readonly_single_input(GSpan(cpp_type, array_data->data, list.size()));
89 }
90 else if (const auto *single_data = std::get_if<nodes::List::SingleData>(&list.data())) {
91 params.add_readonly_single_input(GPointer(cpp_type, single_data->value));
92 }
93}
94
96 const Span<SocketValueVariant *> input_values,
97 const Span<SocketValueVariant *> output_values,
98 GeoNodesUserData *user_data)
99{
100 int64_t max_size = 0;
101 for (const int i : input_values.index_range()) {
102 SocketValueVariant &input_variant = *input_values[i];
103 if (input_variant.is_list()) {
104 if (ListPtr list = input_variant.get<ListPtr>()) {
105 max_size = std::max(max_size, list->size());
106 }
107 }
108 }
109
110 const IndexMask mask(max_size);
111 mf::ParamsBuilder params{fn, &mask};
112 mf::ContextBuilder context;
113 context.user_data(user_data);
114
115 Array<ListPtr, 8> input_lists(input_values.size());
116 for (const int i : input_values.index_range()) {
117 const mf::ParamType param_type = fn.param_type(params.next_param_index());
118 const CPPType &cpp_type = param_type.data_type().single_type();
119 SocketValueVariant &input_variant = *input_values[i];
120 if (input_variant.is_single()) {
121 const void *value = input_variant.get_single_ptr_raw();
122 params.add_readonly_single_input(GPointer(cpp_type, value));
123 }
124 else if (input_variant.is_list()) {
125 ListPtr list_ptr = input_variant.get<ListPtr>();
126 if (!list_ptr || list_ptr->size() == 0) {
127 params.add_readonly_single_input(GPointer(cpp_type, cpp_type.default_value()));
128 continue;
129 }
130 input_lists[i] = create_repeated_list(std::move(list_ptr), max_size);
131 add_list_to_params(params, param_type, *input_lists[i]);
132 }
133 else if (input_variant.is_context_dependent_field()) {
134 fn::GField field = input_variant.extract<fn::GField>();
135 input_lists[i] = evaluate_field_to_list(std::move(field), max_size);
136 add_list_to_params(params, param_type, *input_lists[i]);
137 }
138 else {
139 /* This function should not be called when there are other types like grids in the inputs. */
141 params.add_readonly_single_input(GPointer(cpp_type, cpp_type.default_value()));
142 }
143 }
144 for (const int i : output_values.index_range()) {
145 if (output_values[i] == nullptr) {
146 params.add_ignored_single_output("");
147 continue;
148 }
149 SocketValueVariant &output_variant = *output_values[i];
150 const mf::ParamType param_type = fn.param_type(params.next_param_index());
151 const CPPType &cpp_type = param_type.data_type().single_type();
152 List::ArrayData array_data = List::ArrayData::ForUninitialized(cpp_type, max_size);
153
154 params.add_uninitialized_single_output(GMutableSpan(cpp_type, array_data.data, max_size));
155 output_variant.set(List::create(cpp_type, std::move(array_data), max_size));
156 }
157 fn.call(mask, params, context);
158}
159
160} // namespace blender::nodes
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define POINTER_OFFSET(v, ofs)
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void copy_construct_n(const void *src, void *dst, int64_t n) const
const void * default_value() const
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
int add_with_destination(GField field, GVMutableArray dst)
Definition field.cc:738
const CPPType & cpp_type() const
Definition FN_field.hh:130
static GVArray get_index_varray(const IndexMask &mask)
Definition field.cc:548
GVArray get_varray_for_input(const FieldInput &field_input, const IndexMask &mask, ResourceScope &) const override
static ArrayData ForConstructed(const CPPType &type, int64_t size)
static ArrayData ForUninitialized(const CPPType &type, int64_t size)
const DataVariant & data() const
static ListPtr create(const CPPType &type, DataVariant data, const int64_t size)
const CPPType & cpp_type() const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int count
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
ListPtr evaluate_field_to_list(GField field, const int64_t count)
ImplicitSharingPtr< List > ListPtr
void execute_multi_function_on_value_variant__list(const MultiFunction &fn, const Span< SocketValueVariant * > input_values, const Span< SocketValueVariant * > output_values, GeoNodesUserData *user_data)
static ListPtr create_repeated_list(ListPtr list, const int64_t dst_size)
static void add_list_to_params(mf::ParamsBuilder &params, const mf::ParamType &param_type, const List &list)
i
Definition text_draw.cc:230