27 const bNode *node =
b.node_or_null();
29 if (node !=
nullptr) {
34 value_declaration = &
b.add_input<
decl::Vector>(
"Value").default_value({1.0f, 1.0f, 1.0f});
37 value_declaration = &
b.add_input<
decl::Float>(
"Value").default_value(1.0f);
40 value_declaration = &
b.add_input<
decl::Int>(
"Value").default_value(1);
52 b.add_input<
decl::Int>(
"Group ID",
"Group Index")
55 .description(
"An index used to group values together for multiple separate accumulations");
57 if (node !=
nullptr) {
59 b.add_output(data_type,
"Leading")
60 .field_source_reference_all()
62 "The running total of values in the corresponding group, starting at the first value");
63 b.add_output(data_type,
"Trailing")
64 .field_source_reference_all()
65 .description(
"The running total of values in the corresponding group, starting at zero");
66 b.add_output(data_type,
"Total")
67 .field_source_reference_all()
68 .description(
"The total of all of the values in the corresponding group");
82 data->domain = int16_t(AttrDomain::Point);
90 switch (socket.
type) {
120 bNode &node =
params.add_node(
"GeometryNodeAccumulateField");
121 node_storage(node).data_type = *type;
122 params.update_and_connect_available_socket(node,
"Leading");
128 bNode &node =
params.add_node(
"GeometryNodeAccumulateField");
129 node_storage(node).data_type = *type;
130 params.update_and_connect_available_socket(node,
"Trailing");
136 bNode &node =
params.add_node(
"GeometryNodeAccumulateField");
137 node_storage(node).data_type = *type;
138 params.update_and_connect_available_socket(node,
"Total");
146 bNode &node =
params.add_node(
"GeometryNodeAccumulateField");
147 node_storage(node).data_type = *type;
148 params.update_and_connect_available_socket(node,
"Value");
156 if constexpr (std::is_same_v<T, float4x4>) {
166 if constexpr (std::is_same_v<T, float4x4>) {
188 input_(std::move(
input)),
189 group_index_(std::move(group_index)),
190 source_domain_(source_domain),
191 accumulation_mode_(accumulation_mode)
200 if (domain_size == 0) {
206 evaluator.
add(input_);
207 evaluator.
add(group_index_);
215 using T = decltype(dummy);
216 if constexpr (is_same_any_v<T, int, float, float3, float4x4>) {
217 Array<T> outputs(domain_size);
218 const VArray<T> values = g_values.typed<T>();
220 if (group_indices.is_single()) {
221 T accumulation = AccumulationInfo<T>::initial_value;
222 if (accumulation_mode_ == AccumulationMode::Leading) {
223 for (const int i : values.index_range()) {
224 accumulation = AccumulationInfo<T>::accumulate(accumulation, values[i]);
225 outputs[i] = accumulation;
229 for (const int i : values.index_range()) {
230 outputs[i] = accumulation;
231 accumulation = AccumulationInfo<T>::accumulate(accumulation, values[i]);
236 Map<int, T> accumulations;
237 if (accumulation_mode_ == AccumulationMode::Leading) {
238 for (const int i : values.index_range()) {
239 T &accumulation_value = accumulations.lookup_or_add(
240 group_indices[i], AccumulationInfo<T>::initial_value);
241 accumulation_value = AccumulationInfo<T>::accumulate(accumulation_value, values[i]);
242 outputs[i] = accumulation_value;
246 for (const int i : values.index_range()) {
247 T &accumulation_value = accumulations.lookup_or_add(
248 group_indices[i], AccumulationInfo<T>::initial_value);
249 outputs[i] = accumulation_value;
250 accumulation_value = AccumulationInfo<T>::accumulate(accumulation_value, values[i]);
255 g_output = VArray<T>::from_container(std::move(outputs));
259 return attributes.adapt_domain(std::move(g_output), source_domain_, context.domain());
264 input_.node().for_each_field_input_recursive(
fn);
265 group_index_.node().for_each_field_input_recursive(
fn);
270 return get_default_hash(input_, group_index_, source_domain_, accumulation_mode_);
278 return input_ == other_accumulate->input_ &&
279 group_index_ == other_accumulate->group_index_ &&
280 source_domain_ == other_accumulate->source_domain_ &&
281 accumulation_mode_ == other_accumulate->accumulation_mode_;
289 return source_domain_;
302 input_(std::move(
input)),
303 group_index_(std::move(group_index)),
304 source_domain_(source_domain)
313 if (domain_size == 0) {
319 evaluator.
add(input_);
320 evaluator.
add(group_index_);
328 using T = decltype(dummy);
329 if constexpr (is_same_any_v<T, int, float, float3, float4x4>) {
330 const VArray<T> values = g_values.typed<T>();
331 if (group_indices.is_single()) {
332 T accumulation = AccumulationInfo<T>::initial_value;
333 for (const int i : values.index_range()) {
334 accumulation = AccumulationInfo<T>::accumulate(accumulation, values[i]);
336 g_outputs = VArray<T>::from_single(accumulation, domain_size);
339 Map<int, T> accumulations;
340 for (const int i : values.index_range()) {
341 T &value = accumulations.lookup_or_add(group_indices[i],
342 AccumulationInfo<T>::initial_value);
343 value = AccumulationInfo<T>::accumulate(value, values[i]);
345 Array<T> outputs(domain_size);
346 for (const int i : values.index_range()) {
347 outputs[i] = accumulations.lookup(group_indices[i]);
349 g_outputs = VArray<T>::from_container(std::move(outputs));
354 return attributes.adapt_domain(std::move(g_outputs), source_domain_, context.domain());
359 input_.node().for_each_field_input_recursive(
fn);
360 group_index_.node().for_each_field_input_recursive(
fn);
371 return input_ == other_field->input_ && group_index_ == other_field->group_index_ &&
372 source_domain_ == other_field->source_domain_;
380 return source_domain_;
391 if (
params.output_is_required(
"Leading")) {
394 GField{std::make_shared<AccumulateFieldInput>(
397 if (
params.output_is_required(
"Trailing")) {
400 GField{std::make_shared<AccumulateFieldInput>(
403 if (
params.output_is_required(
"Total")) {
406 GField{std::make_shared<TotalFieldInput>(source_domain, input_field, group_index_field)});
413 {
CD_PROP_FLOAT,
"FLOAT", ICON_NODE_SOCKET_FLOAT,
"Float",
"Add floating point values"},
414 {
CD_PROP_INT32,
"INT", ICON_NODE_SOCKET_INT,
"Integer",
"Add integer values"},
415 {
CD_PROP_FLOAT3,
"FLOAT_VECTOR", ICON_NODE_SOCKET_VECTOR,
"Vector",
"Add 3D vector values"},
418 ICON_NODE_SOCKET_MATRIX,
420 "Multiply transformation matrices"},
421 {0,
nullptr, 0,
nullptr,
nullptr},
427 "Type of data that is accumulated",
438 int(AttrDomain::Point),
447 ntype.
ui_name =
"Accumulate Field";
449 "Add the values of an evaluated field together and output the running total for each "
#define NODE_CLASS_CONVERTER
#define NODE_STORAGE_FUNCS(StorageT)
#define GEO_NODE_ACCUMULATE_FIELD
#define BLI_assert_unreachable()
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
BMesh const char void * data
unsigned long long int uint64_t
const CPPType & type() const
int domain_size(const AttrDomain domain) const
int add(GField field, GVArray *varray_ptr)
const GVArray & get_evaluated(const int field_index) const
BaseSocketDeclarationBuilder & description(std::string value="")
BaseSocketDeclarationBuilder & supports_field()
Vector< SocketDeclaration * > inputs
void * MEM_callocN(size_t len, const char *str)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
void node_register_type(bNodeType &ntype)
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_register()
static void node_declare(NodeDeclarationBuilder &b)
static void node_rna(StructRNA *srna)
static std::optional< eCustomDataType > node_type_from_other_socket(const bNodeSocket &socket)
static void node_init(bNodeTree *, bNode *node)
static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
static void node_geo_exec(GeoNodeExecParams params)
void search_link_ops_for_declarations(GatherLinkSearchOpParams ¶ms, Span< SocketDeclaration * > declarations)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
uint64_t get_default_hash(const T &v, const Args &...args)
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
const EnumPropertyItem rna_enum_attribute_domain_items[]
static MatBase identity()
std::string ui_description
void(* initfunc)(bNodeTree *ntree, bNode *node)
NodeGeometryExecFunction geometry_node_execute
const char * enum_name_legacy
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
NodeDeclareFunction declare
static const T initial_value
static T accumulate(const T &a, const T &b)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)