Blender V4.5
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,
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,
466 std::optional<eCustomDataType> data_type) const;
467
469 {
470 return this->get(domain, std::nullopt);
471 }
472
474 {
475 return this->get(std::nullopt, data_type);
476 }
477
478 template<typename T>
479 AttributeReader<T> get(const std::optional<AttrDomain> domain = std::nullopt) const
480 {
481 const CPPType &cpp_type = CPPType::get<T>();
483 return this->get(domain, data_type).typed<T>();
484 }
485};
486
496 bool (*domain_supported)(const void *owner, AttrDomain domain);
497 int (*domain_size)(const void *owner, AttrDomain domain);
498 std::optional<AttributeDomainAndType> (*builtin_domain_and_type)(const void *owner,
499 StringRef attribute_id);
500 GPointer (*get_builtin_default)(const void *owner, StringRef attribute_id);
501 GAttributeReader (*lookup)(const void *owner, StringRef attribute_id);
502 GVArray (*adapt_domain)(const void *owner,
503 const GVArray &varray,
504 AttrDomain from_domain,
505 AttrDomain to_domain);
506 void (*foreach_attribute)(const void *owner,
507 FunctionRef<void(const AttributeIter &iter)> fn,
508 const AttributeAccessor &accessor);
509 AttributeValidator (*lookup_validator)(const void *owner, StringRef attribute_id);
510 GAttributeWriter (*lookup_for_write)(void *owner, StringRef attribute_id);
511 bool (*remove)(void *owner, StringRef attribute_id);
512 bool (*add)(void *owner,
513 StringRef attribute_id,
514 AttrDomain domain,
515 eCustomDataType data_type,
516 const AttributeInit &initializer);
517};
518
526 protected:
537 void *owner_;
542
543 public:
545 : owner_(const_cast<void *>(owner)), fn_(&fn)
546 {
547 }
548
552 static std::optional<AttributeAccessor> from_id(const ID &id);
553
557 bool contains(StringRef attribute_id) const;
558
562 std::optional<AttributeMetaData> lookup_meta_data(StringRef attribute_id) const;
563
567 bool domain_supported(const AttrDomain domain) const
568 {
569 return fn_->domain_supported(owner_, domain);
570 }
571
575 int domain_size(const AttrDomain domain) const
576 {
577 return fn_->domain_size(owner_, domain);
578 }
579
584 bool is_builtin(const StringRef attribute_id) const
585 {
586 return fn_->builtin_domain_and_type(owner_, attribute_id).has_value();
587 }
588
592 std::optional<AttributeDomainAndType> get_builtin_domain_and_type(const StringRef name) const
593 {
594 return fn_->builtin_domain_and_type(owner_, name);
595 }
596
601 GPointer get_builtin_default(const StringRef attribute_id) const
602 {
603 BLI_assert(this->is_builtin(attribute_id));
604 return fn_->get_builtin_default(owner_, attribute_id);
605 }
606
611 GAttributeReader lookup(const StringRef attribute_id) const
612 {
613 return fn_->lookup(owner_, attribute_id);
614 }
615
620 GAttributeReader lookup(StringRef attribute_id,
621 std::optional<AttrDomain> domain,
622 std::optional<eCustomDataType> data_type) const;
623
628 GAttributeReader lookup(const StringRef attribute_id, const AttrDomain domain) const
629 {
630 return this->lookup(attribute_id, domain, std::nullopt);
631 }
632
637 GAttributeReader lookup(const StringRef attribute_id, const eCustomDataType data_type) const
638 {
639 return this->lookup(attribute_id, std::nullopt, data_type);
640 }
641
646 template<typename T>
648 const std::optional<AttrDomain> domain = std::nullopt) const
649 {
650 const CPPType &cpp_type = CPPType::get<T>();
651 const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type);
652 return this->lookup(attribute_id, domain, data_type).typed<T>();
653 }
654
662 AttrDomain domain,
663 eCustomDataType data_type,
664 const void *default_value = nullptr) const;
665
669 template<typename T>
671 const AttrDomain domain,
672 const T &default_value) const
673 {
674 if (AttributeReader<T> varray = this->lookup<T>(attribute_id, domain)) {
675 return varray;
676 }
677 return {VArray<T>::ForSingle(default_value, this->domain_size(domain)), domain};
678 }
679
684 {
685 return fn_->lookup_validator(owner_, attribute_id);
686 }
687
692 const AttrDomain from_domain,
693 const AttrDomain to_domain) const
694 {
695 return fn_->adapt_domain(owner_, varray, from_domain, to_domain);
696 }
697
701 template<typename T>
703 const AttrDomain from_domain,
704 const AttrDomain to_domain) const
705 {
706 return this->adapt_domain(GVArray(varray), from_domain, to_domain).typed<T>();
707 }
708
713 void foreach_attribute(const FunctionRef<void(const AttributeIter &)> fn) const
714 {
715 if (owner_ != nullptr) {
716 fn_->foreach_attribute(owner_, fn, *this);
717 }
718 }
719
724};
725
731 public:
733 : AttributeAccessor(owner, fn)
734 {
735 }
736
742
747
752 template<typename T> AttributeWriter<T> lookup_for_write(const StringRef attribute_id)
753 {
754 GAttributeWriter attribute = this->lookup_for_write(attribute_id);
755 if (!attribute) {
756 return {};
757 }
758 if (!attribute.varray.type().is<T>()) {
759 return {};
760 }
761 return attribute.typed<T>();
762 }
763
767 template<typename T> SpanAttributeWriter<T> lookup_for_write_span(const StringRef attribute_id)
768 {
769 AttributeWriter<T> attribute = this->lookup_for_write<T>(attribute_id);
770 if (attribute) {
771 return SpanAttributeWriter<T>{std::move(attribute), true};
772 }
773 return {};
774 }
775
779 bool rename(StringRef old_attribute_id, StringRef new_attribute_id);
780
786 bool add(const StringRef attribute_id,
787 const AttrDomain domain,
788 const eCustomDataType data_type,
789 const AttributeInit &initializer)
790 {
791 if (this->contains(attribute_id)) {
792 return false;
793 }
794 return fn_->add(owner_, attribute_id, domain, data_type, initializer);
795 }
796 template<typename T>
797 bool add(const StringRef attribute_id, const AttrDomain domain, const AttributeInit &initializer)
798 {
799 const CPPType &cpp_type = CPPType::get<T>();
800 const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type);
801 return this->add(attribute_id, domain, data_type, initializer);
802 }
803
810 StringRef attribute_id,
811 AttrDomain domain,
812 eCustomDataType data_type,
813 const AttributeInit &initializer = AttributeInitDefaultValue());
814
821 StringRef attribute_id,
822 AttrDomain domain,
823 eCustomDataType data_type,
824 const AttributeInit &initializer = AttributeInitDefaultValue());
825
829 template<typename T>
831 const StringRef attribute_id,
832 const AttrDomain domain,
833 const AttributeInit &initializer = AttributeInitDefaultValue())
834 {
835 const CPPType &cpp_type = CPPType::get<T>();
836 const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type);
837 return this->lookup_or_add_for_write(attribute_id, domain, data_type, initializer).typed<T>();
838 }
839
843 template<typename T>
845 const StringRef attribute_id,
846 const AttrDomain domain,
847 const AttributeInit &initializer = AttributeInitDefaultValue())
848 {
850 attribute_id, domain, initializer);
851 if (attribute) {
852 return SpanAttributeWriter<T>{std::move(attribute), true};
853 }
854 return {};
855 }
856
868 AttrDomain domain,
869 eCustomDataType data_type);
870
874 template<typename T>
876 const AttrDomain domain)
877 {
879 attribute_id, domain, AttributeInitConstruct());
880
881 if (attribute) {
882 return SpanAttributeWriter<T>{std::move(attribute), false};
883 }
884 return {};
885 }
886
892 bool remove(const StringRef attribute_id)
893 {
894 return fn_->remove(owner_, attribute_id);
895 }
896
900 void remove_anonymous();
901};
902
904 /* Expect that if an attribute exists, it is stored as a contiguous array internally anyway. */
909};
910
915 const AttributeAccessor src_attributes,
916 MutableAttributeAccessor dst_attributes,
917 AttrDomainMask domain_mask,
918 const AttributeFilter &attribute_filter = {});
919
921extern const char *no_procedural_access_message;
922
929
930void gather_attributes(AttributeAccessor src_attributes,
931 AttrDomain src_domain,
932 AttrDomain dst_domain,
933 const AttributeFilter &attribute_filter,
934 const IndexMask &selection,
935 MutableAttributeAccessor dst_attributes);
936
940void gather_attributes(AttributeAccessor src_attributes,
941 AttrDomain src_domain,
942 AttrDomain dst_domain,
943 const AttributeFilter &attribute_filter,
945 MutableAttributeAccessor dst_attributes);
946
952void gather_attributes_group_to_group(AttributeAccessor src_attributes,
953 AttrDomain src_domain,
954 AttrDomain dst_domain,
955 const AttributeFilter &attribute_filter,
956 OffsetIndices<int> src_offsets,
957 OffsetIndices<int> dst_offsets,
958 const IndexMask &selection,
959 MutableAttributeAccessor dst_attributes);
960
961void gather_attributes_to_groups(AttributeAccessor src_attributes,
962 AttrDomain src_domain,
963 AttrDomain dst_domain,
964 const AttributeFilter &attribute_filter,
965 OffsetIndices<int> dst_offsets,
966 const IndexMask &src_selection,
967 MutableAttributeAccessor dst_attributes);
968
969void copy_attributes(const AttributeAccessor src_attributes,
970 AttrDomain src_domain,
971 AttrDomain dst_domain,
972 const AttributeFilter &attribute_filter,
973 MutableAttributeAccessor dst_attributes);
974
975void copy_attributes_group_to_group(AttributeAccessor src_attributes,
976 AttrDomain src_domain,
977 AttrDomain dst_domain,
978 const AttributeFilter &attribute_filter,
979 OffsetIndices<int> src_offsets,
980 OffsetIndices<int> dst_offsets,
981 const IndexMask &selection,
982 MutableAttributeAccessor dst_attributes);
983
984void fill_attribute_range_default(MutableAttributeAccessor dst_attributes,
985 AttrDomain domain,
986 const AttributeFilter &attribute_filter,
987 IndexRange range);
988
993 MutableAttributeAccessor &attributes);
994
995} // 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 ForSingle(T value, const int64_t size)
GAttributeReader lookup(const StringRef attribute_id, const eCustomDataType data_type) 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_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) 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
AttributeReader< T > get(const std::optional< AttrDomain > domain=std::nullopt) const
GAttributeReader get(const eCustomDataType data_type) const
AttributeIter(const StringRefNull name, const AttrDomain domain, const eCustomDataType data_type, const FunctionRef< GAttributeReader()> get_fn)
GAttributeReader get() const
const AttributeAccessor * accessor
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GAttributeWriter lookup_or_add_for_write(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
SpanAttributeWriter< T > lookup_for_write_span(const StringRef attribute_id)
GAttributeWriter lookup_for_write(StringRef attribute_id)
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)
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
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, eCustomDataType 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={})
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)
FunctionRef< bool(StringRefNull attribute_id, const AttributeMetaData &meta_data)> AttributeForeachCallback
eCustomDataType attribute_data_type_highest_complexity(Span< eCustomDataType > 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
Definition DNA_ID.h:404
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)
AttributeValidator(* lookup_validator)(const void *owner, StringRef attribute_id)
std::optional< AttributeDomainAndType >(* builtin_domain_and_type)(const void *owner, StringRef attribute_id)
bool(* add)(void *owner, StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer)
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