Blender V5.0
BKE_attribute.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include <functional>
12#include <optional>
13
14#include "BLI_function_ref.hh"
18#include "BLI_offset_indices.hh"
19#include "BLI_set.hh"
21
22#include "BKE_attribute.h"
24
25struct Mesh;
26struct PointCloud;
27namespace blender::fn {
28namespace multi_function {
29class MultiFunction;
30}
31class GField;
32} // namespace blender::fn
33
34namespace blender::bke {
35
37enum class AttrStorageType : int8_t {
42};
43
59
62
63enum class AttrDomain : int8_t {
64 /* Used to choose automatically based on other data. */
65 Auto = -1,
66 /* Mesh, Curve or Point Cloud Point. */
67 Point = 0,
68 /* Mesh Edge. */
69 Edge = 1,
70 /* Mesh Face. */
71 Face = 2,
72 /* Mesh Corner. */
73 Corner = 3,
74 /* A single curve in a larger curve data-block. */
75 Curve = 4,
76 /* Instance. */
78 /* A layer in a grease pencil data-block. */
79 Layer = 6,
80};
81#define ATTR_DOMAIN_NUM 7
82
85
97
103
123
131
138
148
162
168 const void *data = nullptr;
170
175};
176
177/* Returns false when the iteration should be stopped. */
179 FunctionRef<bool(StringRefNull attribute_id, const AttributeMetaData &meta_data)>;
180
185template<typename T> struct AttributeReader {
194
200
201 const VArray<T> &operator*() const &
202 {
203 return this->varray;
204 }
205
207 {
208 return this->varray;
209 }
210
212 {
213 return std::move(this->varray);
214 }
215
216 operator bool() const
217 {
218 return this->varray;
219 }
220};
221
232
233 operator bool() const
234 {
235 return this->function != nullptr;
236 }
237
241};
242
248template<typename T> struct AttributeWriter {
262 std::function<void()> tag_modified_fn;
263
264 operator bool() const
265 {
266 return this->varray;
267 }
268
272 void finish()
273 {
274 if (this->tag_modified_fn) {
275 this->tag_modified_fn();
276 }
277 }
278};
279
285template<typename T> struct SpanAttributeWriter {
297 std::function<void()> tag_modified_fn;
298
300
301 SpanAttributeWriter(AttributeWriter<T> &&other, const bool copy_values_to_span)
302 : span(std::move(other.varray), copy_values_to_span),
303 domain(other.domain),
304 tag_modified_fn(std::move(other.tag_modified_fn))
305 {
306 }
307
308 operator bool() const
309 {
310 return span.varray();
311 }
312
318 void finish()
319 {
320 if (this->span.varray()) {
321 this->span.save();
322 }
323 if (this->tag_modified_fn) {
324 this->tag_modified_fn();
325 }
326 }
327};
328
336
337 operator bool() const
338 {
339 return this->varray;
340 }
341
342 const GVArray &operator*() const &
343 {
344 return this->varray;
345 }
346
348 {
349 return this->varray;
350 }
351
353 {
354 return std::move(this->varray);
355 }
356
357 template<typename T> AttributeReader<T> typed() const
358 {
359 return {varray.typed<T>(), domain, sharing_info};
360 }
361};
362
369 std::function<void()> tag_modified_fn;
370
371 operator bool() const
372 {
373 return this->varray;
374 }
375
376 void finish()
377 {
378 if (this->tag_modified_fn) {
379 this->tag_modified_fn();
380 }
381 }
382
383 template<typename T> AttributeWriter<T> typed() const
384 {
385 return {varray.typed<T>(), domain, tag_modified_fn};
386 }
387};
388
395 std::function<void()> tag_modified_fn;
396
398
399 GSpanAttributeWriter(GAttributeWriter &&other, const bool copy_values_to_span)
400 : span(std::move(other.varray), copy_values_to_span),
401 domain(other.domain),
402 tag_modified_fn(std::move(other.tag_modified_fn))
403 {
404 }
405
406 operator bool() const
407 {
408 return span.varray();
409 }
410
411 void finish()
412 {
413 if (this->span.varray()) {
414 this->span.save();
415 }
416 if (this->tag_modified_fn) {
417 this->tag_modified_fn();
418 }
419 }
420};
421
427 public:
431 bool is_builtin = false;
432 mutable const AttributeAccessor *accessor = nullptr;
433
434 private:
435 FunctionRef<GAttributeReader()> get_fn_;
436 mutable bool stop_iteration_ = false;
437
438 public:
440 const AttrDomain domain,
441 const AttrType data_type,
442 const FunctionRef<GAttributeReader()> get_fn)
443 : name(name), domain(domain), data_type(data_type), get_fn_(get_fn)
444 {
445 }
446
448 void stop() const
449 {
450 stop_iteration_ = true;
451 }
452
453 bool is_stopped() const
454 {
455 return stop_iteration_;
456 }
457
460 {
461 return get_fn_();
462 }
463
465 GAttributeReader get(std::optional<AttrDomain> domain, std::optional<AttrType> data_type) const;
466
468 {
469 return this->get(domain, std::nullopt);
470 }
471
473 {
474 return this->get(std::nullopt, data_type);
475 }
476
477 template<typename T>
478 AttributeReader<T> get(const std::optional<AttrDomain> domain = std::nullopt) const
479 {
480 const CPPType &cpp_type = CPPType::get<T>();
482 return this->get(domain, data_type).typed<T>();
483 }
484};
485
495 bool (*domain_supported)(const void *owner, AttrDomain domain);
496 int (*domain_size)(const void *owner, AttrDomain domain);
497 std::optional<AttributeDomainAndType> (*builtin_domain_and_type)(const void *owner,
498 StringRef attribute_id);
499 GPointer (*get_builtin_default)(const void *owner, StringRef attribute_id);
500 GAttributeReader (*lookup)(const void *owner, StringRef attribute_id);
501 GVArray (*adapt_domain)(const void *owner,
502 const GVArray &varray,
503 AttrDomain from_domain,
504 AttrDomain to_domain);
505 void (*foreach_attribute)(const void *owner,
506 FunctionRef<void(const AttributeIter &iter)> fn,
507 const AttributeAccessor &accessor);
508 AttributeValidator (*lookup_validator)(const void *owner, StringRef attribute_id);
509 GAttributeWriter (*lookup_for_write)(void *owner, StringRef attribute_id);
510 bool (*remove)(void *owner, StringRef attribute_id);
511 bool (*add)(void *owner,
512 StringRef attribute_id,
513 AttrDomain domain,
514 AttrType data_type,
515 const AttributeInit &initializer);
516};
517
525 protected:
536 void *owner_;
541
542 public:
544 : owner_(const_cast<void *>(owner)), fn_(&fn)
545 {
546 }
547
551 static std::optional<AttributeAccessor> from_id(const ID &id);
552
556 bool contains(StringRef attribute_id) const;
557
561 std::optional<AttributeMetaData> lookup_meta_data(StringRef attribute_id) const;
562
566 bool domain_supported(const AttrDomain domain) const
567 {
568 return fn_->domain_supported(owner_, domain);
569 }
570
574 int domain_size(const AttrDomain domain) const
575 {
576 return fn_->domain_size(owner_, domain);
577 }
578
583 bool is_builtin(const StringRef attribute_id) const
584 {
585 return fn_->builtin_domain_and_type(owner_, attribute_id).has_value();
586 }
587
591 std::optional<AttributeDomainAndType> get_builtin_domain_and_type(const StringRef name) const
592 {
593 return fn_->builtin_domain_and_type(owner_, name);
594 }
595
600 GPointer get_builtin_default(const StringRef attribute_id) const
601 {
602 BLI_assert(this->is_builtin(attribute_id));
603 return fn_->get_builtin_default(owner_, attribute_id);
604 }
605
610 GAttributeReader lookup(const StringRef attribute_id) const
611 {
612 return fn_->lookup(owner_, attribute_id);
613 }
614
619 GAttributeReader lookup(StringRef attribute_id,
620 std::optional<AttrDomain> domain,
621 std::optional<AttrType> data_type) const;
622
627 GAttributeReader lookup(const StringRef attribute_id, const AttrDomain domain) const
628 {
629 return this->lookup(attribute_id, domain, std::nullopt);
630 }
631
636 GAttributeReader lookup(const StringRef attribute_id, const AttrType data_type) const
637 {
638 return this->lookup(attribute_id, std::nullopt, data_type);
639 }
640
645 template<typename T>
647 const std::optional<AttrDomain> domain = std::nullopt) const
648 {
649 const CPPType &cpp_type = CPPType::get<T>();
650 const AttrType data_type = cpp_type_to_attribute_type(cpp_type);
651 return this->lookup(attribute_id, domain, data_type).typed<T>();
652 }
653
661 AttrDomain domain,
662 AttrType data_type,
663 const void *default_value = nullptr) const;
664
668 template<typename T>
670 const AttrDomain domain,
671 const T &default_value) const
672 {
673 if (AttributeReader<T> varray = this->lookup<T>(attribute_id, domain)) {
674 return varray;
675 }
676 return {VArray<T>::from_single(default_value, this->domain_size(domain)), domain};
677 }
678
683 {
684 return fn_->lookup_validator(owner_, attribute_id);
685 }
686
691 const AttrDomain from_domain,
692 const AttrDomain to_domain) const
693 {
694 return fn_->adapt_domain(owner_, varray, from_domain, to_domain);
695 }
696
700 template<typename T>
702 const AttrDomain from_domain,
703 const AttrDomain to_domain) const
704 {
705 return this->adapt_domain(GVArray(varray), from_domain, to_domain).typed<T>();
706 }
707
712 void foreach_attribute(const FunctionRef<void(const AttributeIter &)> fn) const
713 {
714 if (owner_ != nullptr) {
715 fn_->foreach_attribute(owner_, fn, *this);
716 }
717 }
718
723};
724
730 public:
732 : AttributeAccessor(owner, fn)
733 {
734 }
735
741
746
751 template<typename T> AttributeWriter<T> lookup_for_write(const StringRef attribute_id)
752 {
753 GAttributeWriter attribute = this->lookup_for_write(attribute_id);
754 if (!attribute) {
755 return {};
756 }
757 if (!attribute.varray.type().is<T>()) {
758 return {};
759 }
760 return attribute.typed<T>();
761 }
762
766 template<typename T> SpanAttributeWriter<T> lookup_for_write_span(const StringRef attribute_id)
767 {
768 AttributeWriter<T> attribute = this->lookup_for_write<T>(attribute_id);
769 if (attribute) {
770 return SpanAttributeWriter<T>{std::move(attribute), true};
771 }
772 return {};
773 }
774
778 bool rename(StringRef old_attribute_id, StringRef new_attribute_id);
779
785 bool add(const StringRef attribute_id,
786 const AttrDomain domain,
787 const AttrType data_type,
788 const AttributeInit &initializer)
789 {
790 if (!this->domain_supported(domain)) {
791 return false;
792 }
793 if (this->contains(attribute_id)) {
794 return false;
795 }
796 return fn_->add(owner_, attribute_id, domain, data_type, initializer);
797 }
798 template<typename T>
799 bool add(const StringRef attribute_id, const AttrDomain domain, const AttributeInit &initializer)
800 {
801 const CPPType &cpp_type = CPPType::get<T>();
802 const AttrType data_type = cpp_type_to_attribute_type(cpp_type);
803 return this->add(attribute_id, domain, data_type, initializer);
804 }
805
812 StringRef attribute_id,
813 AttrDomain domain,
814 AttrType data_type,
815 const AttributeInit &initializer = AttributeInitDefaultValue());
816
823 StringRef attribute_id,
824 AttrDomain domain,
825 AttrType data_type,
826 const AttributeInit &initializer = AttributeInitDefaultValue());
827
831 template<typename T>
833 const StringRef attribute_id,
834 const AttrDomain domain,
835 const AttributeInit &initializer = AttributeInitDefaultValue())
836 {
837 const CPPType &cpp_type = CPPType::get<T>();
838 const AttrType data_type = cpp_type_to_attribute_type(cpp_type);
839 return this->lookup_or_add_for_write(attribute_id, domain, data_type, initializer).typed<T>();
840 }
841
845 template<typename T>
847 const StringRef attribute_id,
848 const AttrDomain domain,
849 const AttributeInit &initializer = AttributeInitDefaultValue())
850 {
852 attribute_id, domain, initializer);
853 if (attribute) {
854 return SpanAttributeWriter<T>{std::move(attribute), true};
855 }
856 return {};
857 }
858
870 AttrDomain domain,
871 AttrType data_type);
872
876 template<typename T>
878 const AttrDomain domain)
879 {
881 attribute_id, domain, AttributeInitConstruct());
882
883 if (attribute) {
884 return SpanAttributeWriter<T>{std::move(attribute), false};
885 }
886 return {};
887 }
888
894 bool remove(const StringRef attribute_id)
895 {
896 return fn_->remove(owner_, attribute_id);
897 }
898
902 void remove_anonymous();
903};
904
906 /* Expect that if an attribute exists, it is stored as a contiguous array internally anyway. */
911};
912
917 const AttributeAccessor src_attributes,
918 MutableAttributeAccessor dst_attributes,
919 AttrDomainMask domain_mask,
920 const AttributeFilter &attribute_filter = {});
921
923extern const char *no_procedural_access_message;
924
931
932void gather_attributes(AttributeAccessor src_attributes,
933 AttrDomain src_domain,
934 AttrDomain dst_domain,
935 const AttributeFilter &attribute_filter,
936 const IndexMask &selection,
937 MutableAttributeAccessor dst_attributes);
938
942void gather_attributes(AttributeAccessor src_attributes,
943 AttrDomain src_domain,
944 AttrDomain dst_domain,
945 const AttributeFilter &attribute_filter,
947 MutableAttributeAccessor dst_attributes);
948
954void gather_attributes_group_to_group(AttributeAccessor src_attributes,
955 AttrDomain src_domain,
956 AttrDomain dst_domain,
957 const AttributeFilter &attribute_filter,
958 OffsetIndices<int> src_offsets,
959 OffsetIndices<int> dst_offsets,
960 const IndexMask &selection,
961 MutableAttributeAccessor dst_attributes);
962
963void gather_attributes_to_groups(AttributeAccessor src_attributes,
964 AttrDomain src_domain,
965 AttrDomain dst_domain,
966 const AttributeFilter &attribute_filter,
967 OffsetIndices<int> dst_offsets,
968 const IndexMask &src_selection,
969 MutableAttributeAccessor dst_attributes);
970
971void copy_attributes(const AttributeAccessor src_attributes,
972 AttrDomain src_domain,
973 AttrDomain dst_domain,
974 const AttributeFilter &attribute_filter,
975 MutableAttributeAccessor dst_attributes);
976
977void copy_attributes_group_to_group(AttributeAccessor src_attributes,
978 AttrDomain src_domain,
979 AttrDomain dst_domain,
980 const AttributeFilter &attribute_filter,
981 OffsetIndices<int> src_offsets,
982 OffsetIndices<int> dst_offsets,
983 const IndexMask &selection,
984 MutableAttributeAccessor dst_attributes);
985
986void fill_attribute_range_default(MutableAttributeAccessor dst_attributes,
987 AttrDomain domain,
988 const AttributeFilter &attribute_filter,
989 IndexRange range);
990
995 MutableAttributeAccessor &attributes);
996
997} // namespace blender::bke
Generic geometry attributes built on CustomData.
AttrDomainMask
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_STRUCT_EQUALITY_OPERATORS_2(Type, m1, m2)
AttrDomain
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static const CPPType & get()
bool is() const
const GVMutableArray & varray() const
const VMutableArray< T > & varray() const
static VArray from_single(T value, const int64_t size)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
bool is_builtin(const StringRef attribute_id) const
std::optional< AttributeDomainAndType > get_builtin_domain_and_type(const StringRef name) const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
AttributeReader< T > lookup(const StringRef attribute_id, const std::optional< AttrDomain > domain=std::nullopt) const
AttributeValidator lookup_validator(const StringRef attribute_id) const
GPointer get_builtin_default(const StringRef attribute_id) const
bool contains(StringRef attribute_id) const
AttributeReader< T > lookup_or_default(const StringRef attribute_id, const AttrDomain domain, const T &default_value) const
static std::optional< AttributeAccessor > from_id(const ID &id)
GVArray adapt_domain(const GVArray &varray, const AttrDomain from_domain, const AttrDomain to_domain) const
GAttributeReader lookup(const StringRef attribute_id) const
VArray< T > adapt_domain(const VArray< T > &varray, const AttrDomain from_domain, const AttrDomain to_domain) const
Set< StringRefNull > all_ids() const
GAttributeReader lookup(const StringRef attribute_id, const AttrType data_type) const
GAttributeReader lookup(const StringRef attribute_id, const AttrDomain domain) const
bool domain_supported(const AttrDomain domain) const
AttributeAccessor(const void *owner, const AttributeAccessorFunctions &fn)
int domain_size(const AttrDomain domain) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
const AttributeAccessorFunctions * fn_
GAttributeReader get(const AttrDomain domain) const
GAttributeReader get(const AttrType data_type) const
AttributeReader< T > get(const std::optional< AttrDomain > domain=std::nullopt) const
AttributeIter(const StringRefNull name, const AttrDomain domain, const AttrType data_type, const FunctionRef< GAttributeReader()> get_fn)
GAttributeReader get() const
const AttributeAccessor * accessor
SpanAttributeWriter< T > lookup_for_write_span(const StringRef attribute_id)
GAttributeWriter lookup_for_write(StringRef attribute_id)
bool add(const StringRef attribute_id, const AttrDomain domain, const AttrType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
AttributeWriter< T > lookup_or_add_for_write(const StringRef attribute_id, const AttrDomain domain, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
SpanAttributeWriter< T > lookup_or_add_for_write_only_span(const StringRef attribute_id, const AttrDomain domain)
GAttributeWriter lookup_or_add_for_write(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool rename(StringRef old_attribute_id, StringRef new_attribute_id)
bool add(const StringRef attribute_id, const AttrDomain domain, const AttributeInit &initializer)
AttributeWriter< T > lookup_for_write(const StringRef attribute_id)
MutableAttributeAccessor(void *owner, const AttributeAccessorFunctions &fn)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
SpanAttributeWriter< T > lookup_or_add_for_write_span(const StringRef attribute_id, const AttrDomain domain, const AttributeInit &initializer=AttributeInitDefaultValue())
static ushort indices[]
#define T
Vector< AttributeTransferData > retrieve_attributes_for_transfer(const AttributeAccessor src_attributes, MutableAttributeAccessor dst_attributes, AttrDomainMask domain_mask, const AttributeFilter &attribute_filter={})
FunctionRef< bool(StringRefNull attribute_id, const AttributeMetaData &meta_data)> AttributeForeachCallback
void fill_attribute_range_default(MutableAttributeAccessor dst_attributes, AttrDomain domain, const AttributeFilter &attribute_filter, IndexRange range)
void gather_attributes_to_groups(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, OffsetIndices< int > dst_offsets, const IndexMask &src_selection, MutableAttributeAccessor dst_attributes)
bool allow_procedural_attribute_access(StringRef attribute_name)
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
void copy_attributes(const AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, MutableAttributeAccessor dst_attributes)
const char * no_procedural_access_message
void gather_attributes(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, const IndexMask &selection, MutableAttributeAccessor dst_attributes)
AttrType attribute_data_type_highest_complexity(Span< AttrType > data_types)
AttrDomain attribute_domain_highest_priority(Span< AttrDomain > domains)
void transform_custom_normal_attribute(const float4x4 &transform, MutableAttributeAccessor &attributes)
const CPPType * custom_data_type_to_cpp_type(eCustomDataType type)
void gather_attributes_group_to_group(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, OffsetIndices< int > src_offsets, OffsetIndices< int > dst_offsets, const IndexMask &selection, MutableAttributeAccessor dst_attributes)
void copy_attributes_group_to_group(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, OffsetIndices< int > src_offsets, OffsetIndices< int > dst_offsets, const IndexMask &selection, MutableAttributeAccessor dst_attributes)
AttrType cpp_type_to_attribute_type(const CPPType &type)
const CPPType & attribute_type_to_cpp_type(AttrType type)
MatBase< float, 4, 4 > float4x4
const char * name
Definition DNA_ID.h:414
GPointer(* get_builtin_default)(const void *owner, StringRef attribute_id)
GVArray(* adapt_domain)(const void *owner, const GVArray &varray, AttrDomain from_domain, AttrDomain to_domain)
void(* foreach_attribute)(const void *owner, FunctionRef< void(const AttributeIter &iter)> fn, const AttributeAccessor &accessor)
bool(* remove)(void *owner, StringRef attribute_id)
bool(* domain_supported)(const void *owner, AttrDomain domain)
GAttributeWriter(* lookup_for_write)(void *owner, StringRef attribute_id)
bool(* add)(void *owner, StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer)
AttributeValidator(* lookup_validator)(const void *owner, StringRef attribute_id)
std::optional< AttributeDomainAndType >(* builtin_domain_and_type)(const void *owner, StringRef attribute_id)
int(* domain_size)(const void *owner, AttrDomain domain)
GAttributeReader(* lookup)(const void *owner, StringRef attribute_id)
AttributeInitShared(const void *data, const ImplicitSharingInfo &sharing_info)
const ImplicitSharingInfo * sharing_info
const VArray< T > & operator*() const &
const ImplicitSharingInfo * sharing_info
const fn::multi_function::MultiFunction * function
fn::GField validate_field_if_necessary(const fn::GField &field) const
std::function< void()> tag_modified_fn
const ImplicitSharingInfo * sharing_info
AttributeReader< T > typed() const
const GVArray & operator*() const &
AttributeWriter< T > typed() const
std::function< void()> tag_modified_fn
GSpanAttributeWriter(GAttributeWriter &&other, const bool copy_values_to_span)
std::function< void()> tag_modified_fn
SpanAttributeWriter(AttributeWriter< T > &&other, const bool copy_values_to_span)
std::function< void()> tag_modified_fn