Blender  V3.3
attribute_access.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <utility>
4 
5 #include "BKE_attribute_math.hh"
6 #include "BKE_customdata.h"
7 #include "BKE_deform.h"
8 #include "BKE_geometry_fields.hh"
9 #include "BKE_geometry_set.hh"
10 #include "BKE_mesh.h"
11 #include "BKE_pointcloud.h"
12 #include "BKE_type_conversions.hh"
13 
14 #include "DNA_mesh_types.h"
15 #include "DNA_meshdata_types.h"
16 #include "DNA_pointcloud_types.h"
17 
18 #include "BLI_color.hh"
19 #include "BLI_math_vec_types.hh"
20 #include "BLI_span.hh"
21 
22 #include "BLT_translation.h"
23 
24 #include "CLG_log.h"
25 
27 
28 using blender::float3;
30 using blender::GSpan;
32 using blender::Set;
33 using blender::StringRef;
36 
37 namespace blender::bke {
38 
39 std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id)
40 {
41  if (attribute_id.is_named()) {
42  stream << attribute_id.name();
43  }
44  else if (attribute_id.is_anonymous()) {
45  const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
46  stream << "<" << BKE_anonymous_attribute_id_debug_name(&anonymous_id) << ">";
47  }
48  else {
49  stream << "<none>";
50  }
51  return stream;
52 }
53 
55  "This attribute can not be accessed in a procedural context";
56 
58 {
59  return !attribute_name.startswith(".selection");
60 }
61 
63 {
64  switch (data_type) {
65  case CD_PROP_BOOL:
66  return 0;
67  case CD_PROP_INT8:
68  return 1;
69  case CD_PROP_INT32:
70  return 2;
71  case CD_PROP_FLOAT:
72  return 3;
73  case CD_PROP_FLOAT2:
74  return 4;
75  case CD_PROP_FLOAT3:
76  return 5;
77  case CD_PROP_BYTE_COLOR:
78  return 6;
79  case CD_PROP_COLOR:
80  return 7;
81 #if 0 /* These attribute types are not supported yet. */
82  case CD_PROP_STRING:
83  return 6;
84 #endif
85  default:
86  /* Only accept "generic" custom data types used by the attribute system. */
88  return 0;
89  }
90 }
91 
93 {
94  int highest_complexity = INT_MIN;
95  eCustomDataType most_complex_type = CD_PROP_COLOR;
96 
97  for (const eCustomDataType data_type : data_types) {
98  const int complexity = attribute_data_type_complexity(data_type);
99  if (complexity > highest_complexity) {
100  highest_complexity = complexity;
101  most_complex_type = data_type;
102  }
103  }
104 
105  return most_complex_type;
106 }
107 
112 static int attribute_domain_priority(const eAttrDomain domain)
113 {
114  switch (domain) {
116  return 0;
117  case ATTR_DOMAIN_CURVE:
118  return 1;
119  case ATTR_DOMAIN_FACE:
120  return 2;
121  case ATTR_DOMAIN_EDGE:
122  return 3;
123  case ATTR_DOMAIN_POINT:
124  return 4;
125  case ATTR_DOMAIN_CORNER:
126  return 5;
127  default:
128  /* Domain not supported in nodes yet. */
130  return 0;
131  }
132 }
133 
135 {
136  int highest_priority = INT_MIN;
137  eAttrDomain highest_priority_domain = ATTR_DOMAIN_CORNER;
138 
139  for (const eAttrDomain domain : domains) {
140  const int priority = attribute_domain_priority(domain);
141  if (priority > highest_priority) {
142  highest_priority = priority;
143  highest_priority_domain = domain;
144  }
145  }
146 
147  return highest_priority_domain;
148 }
149 
151 {
152  if (layer.anonymous_id != nullptr) {
153  return layer.anonymous_id;
154  }
155  return layer.name;
156 }
157 
159  const eCustomDataType data_type,
160  const int domain_num,
161  const AttributeInit &initializer)
162 {
163  switch (initializer.type) {
165  void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num);
166  return data != nullptr;
167  }
169  void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num);
170  if (data == nullptr) {
171  return false;
172  }
173  const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
175  return true;
176  }
178  void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
179  void *data = CustomData_add_layer(
180  &custom_data, data_type, CD_ASSIGN, source_data, domain_num);
181  if (data == nullptr) {
182  MEM_freeN(source_data);
183  return false;
184  }
185  return true;
186  }
187  }
188 
190  return false;
191 }
192 
193 static void *add_generic_custom_data_layer(CustomData &custom_data,
194  const eCustomDataType data_type,
195  const eCDAllocType alloctype,
196  void *layer_data,
197  const int domain_num,
198  const AttributeIDRef &attribute_id)
199 {
200  if (attribute_id.is_named()) {
201  char attribute_name_c[MAX_NAME];
202  attribute_id.name().copy(attribute_name_c);
204  &custom_data, data_type, alloctype, layer_data, domain_num, attribute_name_c);
205  }
206  const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
208  &custom_data, data_type, alloctype, layer_data, domain_num, &anonymous_id);
209 }
210 
212  CustomData &custom_data,
213  const eCustomDataType data_type,
214  const int domain_num,
215  const AttributeInit &initializer)
216 {
217  const int old_layer_num = custom_data.totlayer;
218  switch (initializer.type) {
221  custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id);
222  break;
223  }
226  custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id);
227  if (data != nullptr) {
228  const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
230  }
231  break;
232  }
234  void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
236  custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id);
237  if (source_data != nullptr && data == nullptr) {
238  MEM_freeN(source_data);
239  }
240  break;
241  }
242  }
243  return old_layer_num < custom_data.totlayer;
244 }
245 
247  const AttributeIDRef &attribute_id)
248 {
249  if (!attribute_id) {
250  return false;
251  }
252  if (attribute_id.is_anonymous()) {
253  return layer.anonymous_id == &attribute_id.anonymous_id();
254  }
255  return layer.name == attribute_id.name();
256 }
257 
259 {
260  const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
261  if (custom_data == nullptr) {
262  return {};
263  }
264 
265  const void *data = nullptr;
266  bool found_attribute = false;
267  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
268  if (stored_as_named_attribute_) {
269  if (layer.name == name_) {
270  data = layer.data;
271  found_attribute = true;
272  break;
273  }
274  }
275  else if (layer.type == stored_type_) {
276  data = layer.data;
277  found_attribute = true;
278  break;
279  }
280  }
281  if (!found_attribute) {
282  return {};
283  }
284  const int element_num = custom_data_access_.get_element_num(owner);
285  return as_read_attribute_(data, element_num);
286 }
287 
289 {
290  if (writable_ != Writable) {
291  return {};
292  }
293  CustomData *custom_data = custom_data_access_.get_custom_data(owner);
294  if (custom_data == nullptr) {
295  return {};
296  }
297  const int element_num = custom_data_access_.get_element_num(owner);
298 
299  void *data = nullptr;
300  bool found_attribute = false;
301  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
302  if (stored_as_named_attribute_) {
303  if (layer.name == name_) {
304  data = layer.data;
305  found_attribute = true;
306  break;
307  }
308  }
309  else if (layer.type == stored_type_) {
310  data = layer.data;
311  found_attribute = true;
312  break;
313  }
314  }
315  if (!found_attribute) {
316  return {};
317  }
318 
319  if (data != nullptr) {
320  void *new_data;
321  if (stored_as_named_attribute_) {
323  custom_data, stored_type_, name_.c_str(), element_num);
324  }
325  else {
326  new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, element_num);
327  }
328 
329  if (data != new_data) {
330  if (custom_data_access_.update_custom_data_pointers) {
331  custom_data_access_.update_custom_data_pointers(owner);
332  }
333  data = new_data;
334  }
335  }
336 
337  std::function<void()> tag_modified_fn;
338  if (update_on_change_ != nullptr) {
339  tag_modified_fn = [owner, update = update_on_change_]() { update(owner); };
340  }
341 
342  return {as_write_attribute_(data, element_num), domain_, std::move(tag_modified_fn)};
343 }
344 
346 {
347  if (deletable_ != Deletable) {
348  return false;
349  }
350  CustomData *custom_data = custom_data_access_.get_custom_data(owner);
351  if (custom_data == nullptr) {
352  return {};
353  }
354 
355  auto update = [&]() {
356  if (update_on_change_ != nullptr) {
357  update_on_change_(owner);
358  }
359  };
360 
361  const int element_num = custom_data_access_.get_element_num(owner);
362  if (stored_as_named_attribute_) {
363  if (CustomData_free_layer_named(custom_data, name_.c_str(), element_num)) {
364  if (custom_data_access_.update_custom_data_pointers) {
365  custom_data_access_.update_custom_data_pointers(owner);
366  }
367  update();
368  return true;
369  }
370  return false;
371  }
372 
373  const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
374  if (CustomData_free_layer(custom_data, stored_type_, element_num, layer_index)) {
375  if (custom_data_access_.update_custom_data_pointers) {
376  custom_data_access_.update_custom_data_pointers(owner);
377  }
378  update();
379  return true;
380  }
381 
382  return false;
383 }
384 
386  const AttributeInit &initializer) const
387 {
388  if (createable_ != Creatable) {
389  return false;
390  }
391  CustomData *custom_data = custom_data_access_.get_custom_data(owner);
392  if (custom_data == nullptr) {
393  return false;
394  }
395 
396  const int element_num = custom_data_access_.get_element_num(owner);
397  bool success;
398  if (stored_as_named_attribute_) {
399  if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) {
400  /* Exists already. */
401  return false;
402  }
404  name_, *custom_data, stored_type_, element_num, initializer);
405  }
406  else {
407  if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
408  /* Exists already. */
409  return false;
410  }
412  *custom_data, stored_type_, element_num, initializer);
413  }
414  if (success) {
415  if (custom_data_access_.update_custom_data_pointers) {
416  custom_data_access_.update_custom_data_pointers(owner);
417  }
418  }
419  return success;
420 }
421 
422 bool BuiltinCustomDataLayerProvider::exists(const void *owner) const
423 {
424  const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
425  if (custom_data == nullptr) {
426  return false;
427  }
428  if (stored_as_named_attribute_) {
429  return CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()) != nullptr;
430  }
431  return CustomData_get_layer(custom_data, stored_type_) != nullptr;
432 }
433 
435  const void *owner, const AttributeIDRef &attribute_id) const
436 {
437  const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
438  if (custom_data == nullptr) {
439  return {};
440  }
441  const int element_num = custom_data_access_.get_element_num(owner);
442  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
443  if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
444  continue;
445  }
447  if (type == nullptr) {
448  continue;
449  }
450  GSpan data{*type, layer.data, element_num};
451  return {GVArray::ForSpan(data), domain_};
452  }
453  return {};
454 }
455 
457  void *owner, const AttributeIDRef &attribute_id) const
458 {
459  CustomData *custom_data = custom_data_access_.get_custom_data(owner);
460  if (custom_data == nullptr) {
461  return {};
462  }
463  const int element_num = custom_data_access_.get_element_num(owner);
464  for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
465  if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
466  continue;
467  }
468  if (attribute_id.is_named()) {
470  custom_data, layer.type, layer.name, element_num);
471  }
472  else {
474  custom_data, layer.type, &attribute_id.anonymous_id(), element_num);
475  }
477  if (type == nullptr) {
478  continue;
479  }
480  GMutableSpan data{*type, layer.data, element_num};
481  return {GVMutableArray::ForSpan(data), domain_};
482  }
483  return {};
484 }
485 
486 bool CustomDataAttributeProvider::try_delete(void *owner, const AttributeIDRef &attribute_id) const
487 {
488  CustomData *custom_data = custom_data_access_.get_custom_data(owner);
489  if (custom_data == nullptr) {
490  return false;
491  }
492  const int element_num = custom_data_access_.get_element_num(owner);
493  ;
494  for (const int i : IndexRange(custom_data->totlayer)) {
495  const CustomDataLayer &layer = custom_data->layers[i];
496  if (this->type_is_supported((eCustomDataType)layer.type) &&
497  custom_data_layer_matches_attribute_id(layer, attribute_id)) {
498  CustomData_free_layer(custom_data, layer.type, element_num, i);
499  return true;
500  }
501  }
502  return false;
503 }
504 
506  const AttributeIDRef &attribute_id,
507  const eAttrDomain domain,
508  const eCustomDataType data_type,
509  const AttributeInit &initializer) const
510 {
511  if (domain_ != domain) {
512  return false;
513  }
514  if (!this->type_is_supported(data_type)) {
515  return false;
516  }
517  CustomData *custom_data = custom_data_access_.get_custom_data(owner);
518  if (custom_data == nullptr) {
519  return false;
520  }
521  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
522  if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
523  return false;
524  }
525  }
526  const int element_num = custom_data_access_.get_element_num(owner);
528  attribute_id, *custom_data, data_type, element_num, initializer);
529  return true;
530 }
531 
534 {
535  const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
536  if (custom_data == nullptr) {
537  return true;
538  }
539  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
540  const eCustomDataType data_type = (eCustomDataType)layer.type;
541  if (this->type_is_supported(data_type)) {
542  AttributeMetaData meta_data{domain_, data_type};
543  const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer);
544  if (!callback(attribute_id, meta_data)) {
545  return false;
546  }
547  }
548  }
549  return true;
550 }
551 
553  const void *owner, const AttributeIDRef &attribute_id) const
554 {
555  const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
556  if (custom_data == nullptr) {
557  return {};
558  }
559  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
560  if (layer.type == stored_type_) {
561  if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
562  const int domain_num = custom_data_access_.get_element_num(owner);
563  return {as_read_attribute_(layer.data, domain_num), domain_};
564  }
565  }
566  }
567  return {};
568 }
569 
571  void *owner, const AttributeIDRef &attribute_id) const
572 {
573  CustomData *custom_data = custom_data_access_.get_custom_data(owner);
574  if (custom_data == nullptr) {
575  return {};
576  }
577  for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
578  if (layer.type == stored_type_) {
579  if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
580  const int element_num = custom_data_access_.get_element_num(owner);
581  void *data_old = layer.data;
583  custom_data, stored_type_, layer.name, element_num);
584  if (data_old != data_new) {
585  if (custom_data_access_.update_custom_data_pointers) {
586  custom_data_access_.update_custom_data_pointers(owner);
587  }
588  }
589  return {as_write_attribute_(layer.data, element_num), domain_};
590  }
591  }
592  }
593  return {};
594 }
595 
597  const AttributeIDRef &attribute_id) const
598 {
599  CustomData *custom_data = custom_data_access_.get_custom_data(owner);
600  if (custom_data == nullptr) {
601  return false;
602  }
603  for (const int i : IndexRange(custom_data->totlayer)) {
604  const CustomDataLayer &layer = custom_data->layers[i];
605  if (layer.type == stored_type_) {
606  if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
607  const int element_num = custom_data_access_.get_element_num(owner);
608  CustomData_free_layer(custom_data, stored_type_, element_num, i);
609  if (custom_data_access_.update_custom_data_pointers) {
610  custom_data_access_.update_custom_data_pointers(owner);
611  }
612  return true;
613  }
614  }
615  }
616  return false;
617 }
618 
620  const void *owner, const AttributeForeachCallback callback) const
621 {
622  const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
623  if (custom_data == nullptr) {
624  return true;
625  }
626  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
627  if (layer.type == stored_type_) {
628  AttributeMetaData meta_data{domain_, attribute_type_};
629  if (!callback(layer.name, meta_data)) {
630  return false;
631  }
632  }
633  }
634  return true;
635 }
636 
638  const FunctionRef<void(eAttrDomain)> callback) const
639 {
640  callback(domain_);
641 }
642 
644 {
646  size_ = 0;
647 }
648 
650 {
651  CustomData_free(&data, size_);
652 }
653 
655 {
656  size_ = other.size_;
657  CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, size_);
658 }
659 
661 {
662  size_ = other.size_;
663  data = other.data;
664  CustomData_reset(&other.data);
665 }
666 
668 {
669  if (this != &other) {
670  CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, other.size_);
671  size_ = other.size_;
672  }
673 
674  return *this;
675 }
676 
677 std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id) const
678 {
679  for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
680  if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
681  const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
682  BLI_assert(cpp_type != nullptr);
683  return GSpan(*cpp_type, layer.data, size_);
684  }
685  }
686  return {};
687 }
688 
690  const eCustomDataType data_type,
691  const void *default_value) const
692 {
694 
695  std::optional<GSpan> attribute = this->get_for_read(attribute_id);
696  if (!attribute) {
697  const int domain_num = this->size_;
698  return GVArray::ForSingle(
699  *type, domain_num, (default_value == nullptr) ? type->default_value() : default_value);
700  }
701 
702  if (attribute->type() == *type) {
703  return GVArray::ForSpan(*attribute);
704  }
705  const blender::bke::DataTypeConversions &conversions =
707  return conversions.try_convert(GVArray::ForSpan(*attribute), *type);
708 }
709 
710 std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id)
711 {
713  if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
714  const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
715  BLI_assert(cpp_type != nullptr);
716  return GMutableSpan(*cpp_type, layer.data, size_);
717  }
718  }
719  return {};
720 }
721 
723  const eCustomDataType data_type)
724 {
726  data, data_type, CD_DEFAULT, nullptr, size_, attribute_id);
727  return result != nullptr;
728 }
729 
731  const eCustomDataType data_type,
732  void *buffer)
733 {
735  data, data_type, CD_ASSIGN, buffer, size_, attribute_id);
736  return result != nullptr;
737 }
738 
740 {
741  for (const int i : IndexRange(data.totlayer)) {
742  const CustomDataLayer &layer = data.layers[i];
743  if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
744  CustomData_free_layer(&data, layer.type, size_, i);
745  return true;
746  }
747  }
748  return false;
749 }
750 
752 {
753  size_ = size;
755 }
756 
758 {
759  CustomData_free(&data, size_);
760  size_ = 0;
761 }
762 
764  const eAttrDomain domain) const
765 {
766  for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
767  AttributeMetaData meta_data{domain, (eCustomDataType)layer.type};
768  const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer);
769  if (!callback(attribute_id, meta_data)) {
770  return false;
771  }
772  }
773  return true;
774 }
775 
777 {
778  BLI_assert(new_order.size() == data.totlayer);
779 
780  Map<AttributeIDRef, int> old_order;
781  old_order.reserve(data.totlayer);
783  for (const int i : old_layers.index_range()) {
784  old_order.add_new(attribute_id_from_custom_data_layer(old_layers[i]), i);
785  }
786 
788  for (const int i : layers.index_range()) {
789  const int old_index = old_order.lookup(new_order[i]);
790  layers[i] = old_layers[old_index];
791  }
792 
794 }
795 
796 /* -------------------------------------------------------------------- */
801  const blender::CPPType &to_type)
802 {
803  const blender::bke::DataTypeConversions &conversions =
805  return conversions.try_convert(std::move(varray), to_type);
806 }
807 
809  IndexMask mask,
810  ResourceScope &UNUSED(scope)) const
811 {
812  if (const GeometryComponentFieldContext *geometry_context =
813  dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
814  const GeometryComponent &component = geometry_context->geometry_component();
815  const eAttrDomain domain = geometry_context->domain();
816  return this->get_varray_for_context(component, domain, mask);
817  }
818  return {};
819 }
820 
822  const eAttrDomain domain,
823  IndexMask UNUSED(mask)) const
824 {
826  if (auto attributes = component.attributes()) {
827  return attributes->lookup(name_, domain, data_type);
828  }
829  return {};
830 }
831 
833 {
834  std::stringstream ss;
835  ss << '"' << name_ << '"' << TIP_(" attribute from geometry");
836  return ss.str();
837 }
838 
840 {
841  return get_default_hash_2(name_, type_);
842 }
843 
845 {
846  if (const AttributeFieldInput *other_typed = dynamic_cast<const AttributeFieldInput *>(&other)) {
847  return name_ == other_typed->name_ && type_ == other_typed->type_;
848  }
849  return false;
850 }
851 
853 {
854  switch (domain) {
855  case ATTR_DOMAIN_POINT:
857  return "id";
858  default:
859  return "";
860  }
861 }
862 
864  const eAttrDomain domain,
865  IndexMask mask) const
866 {
867 
868  const StringRef name = get_random_id_attribute_name(domain);
869  if (auto attributes = component.attributes()) {
870  if (GVArray attribute = attributes->lookup(name, domain, CD_PROP_INT32)) {
871  return attribute;
872  }
873  }
874 
875  /* Use the index as the fallback if no random ID attribute exists. */
877 }
878 
880 {
881  return TIP_("ID / Index");
882 }
883 
885 {
886  /* All random ID attribute inputs are the same within the same evaluation context. */
887  return 92386459827;
888 }
889 
891 {
892  /* All random ID attribute inputs are the same within the same evaluation context. */
893  return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr;
894 }
895 
897  const eAttrDomain domain,
898  IndexMask UNUSED(mask)) const
899 {
901  return component.attributes()->lookup(anonymous_id_.get(), domain, data_type);
902 }
903 
905 {
906  std::stringstream ss;
907  ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_;
908  return ss.str();
909 }
910 
912 {
913  return get_default_hash_2(anonymous_id_.get(), type_);
914 }
915 
917 {
918  if (const AnonymousAttributeFieldInput *other_typed =
919  dynamic_cast<const AnonymousAttributeFieldInput *>(&other)) {
920  return anonymous_id_.get() == other_typed->anonymous_id_.get() && type_ == other_typed->type_;
921  }
922  return false;
923 }
924 
926  const std::optional<eAttrDomain> domain,
927  const std::optional<eCustomDataType> data_type) const
928 {
929  GAttributeReader attribute = this->lookup(attribute_id);
930  if (!attribute) {
931  return {};
932  }
933  GVArray varray = std::move(attribute.varray);
934  if (domain.has_value()) {
935  if (attribute.domain != domain) {
936  varray = this->adapt_domain(varray, attribute.domain, *domain);
937  if (!varray) {
938  return {};
939  }
940  }
941  }
942  if (data_type.has_value()) {
943  const CPPType &type = *custom_data_type_to_cpp_type(*data_type);
944  if (varray.type() != type) {
945  varray = try_adapt_data_type(std::move(varray), type);
946  if (!varray) {
947  return {};
948  }
949  }
950  }
951  return varray;
952 }
953 
955  const eAttrDomain domain,
956  const eCustomDataType data_type,
957  const void *default_value) const
958 {
959  GVArray varray = this->lookup(attribute_id, domain, data_type);
960  if (varray) {
961  return varray;
962  }
963  const CPPType &type = *custom_data_type_to_cpp_type(data_type);
964  const int64_t domain_size = this->domain_size(domain);
965  if (default_value == nullptr) {
966  return GVArray::ForSingleRef(type, domain_size, type.default_value());
967  }
968  return GVArray::ForSingle(type, domain_size, default_value);
969 }
970 
972 {
974  this->for_all(
975  [&](const AttributeIDRef &attribute_id, const AttributeMetaData & /* meta_data */) {
976  ids.add(attribute_id);
977  return true;
978  });
979  return ids;
980 }
981 
983 {
985  for (const AttributeIDRef &id : this->all_ids()) {
986  if (id.is_anonymous()) {
987  anonymous_ids.append(&id.anonymous_id());
988  }
989  }
990 
991  while (!anonymous_ids.is_empty()) {
992  this->remove(anonymous_ids.pop_last());
993  }
994 }
995 
999 #ifdef DEBUG
1000 struct FinishCallChecker {
1001  std::string name;
1002  bool finish_called = false;
1003  std::function<void()> real_finish_fn;
1004 
1005  ~FinishCallChecker()
1006  {
1007  if (!this->finish_called) {
1008  std::cerr << "Forgot to call `finish()` for '" << this->name << "'.\n";
1009  }
1010  }
1011 };
1012 #endif
1013 
1015 {
1017  /* Check that the #finish method is called in debug builds. */
1018 #ifdef DEBUG
1019  if (attribute) {
1020  auto checker = std::make_shared<FinishCallChecker>();
1021  if (attribute_id.is_named()) {
1022  checker->name = attribute_id.name();
1023  }
1024  else {
1025  checker->name = BKE_anonymous_attribute_id_debug_name(&attribute_id.anonymous_id());
1026  }
1027  checker->real_finish_fn = attribute.tag_modified_fn;
1028  attribute.tag_modified_fn = [checker]() {
1029  if (checker->real_finish_fn) {
1030  checker->real_finish_fn();
1031  }
1032  checker->finish_called = true;
1033  };
1034  }
1035 #endif
1036  return attribute;
1037 }
1038 
1040  const AttributeIDRef &attribute_id,
1041  const eAttrDomain domain,
1042  const eCustomDataType data_type,
1043  const AttributeInit &initializer)
1044 {
1045  std::optional<AttributeMetaData> meta_data = this->lookup_meta_data(attribute_id);
1046  if (meta_data.has_value()) {
1047  if (meta_data->domain == domain && meta_data->data_type == data_type) {
1048  return this->lookup_for_write(attribute_id);
1049  }
1050  return {};
1051  }
1052  if (this->add(attribute_id, domain, data_type, initializer)) {
1053  return this->lookup_for_write(attribute_id);
1054  }
1055  return {};
1056 }
1057 
1059  const AttributeIDRef &attribute_id,
1060  const eAttrDomain domain,
1061  const eCustomDataType data_type,
1062  const AttributeInit &initializer)
1063 {
1065  attribute_id, domain, data_type, initializer);
1066  if (attribute) {
1067  return GSpanAttributeWriter{std::move(attribute), true};
1068  }
1069  return {};
1070 }
1071 
1073  const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
1074 {
1075  GAttributeWriter attribute = this->lookup_or_add_for_write(attribute_id, domain, data_type);
1076  if (attribute) {
1077  return GSpanAttributeWriter{std::move(attribute), false};
1078  }
1079  return {};
1080 }
1081 
1083  const bke::AttributeAccessor src_attributes,
1084  bke::MutableAttributeAccessor dst_attributes,
1085  const eAttrDomainMask domain_mask,
1086  const Set<std::string> &skip)
1087 {
1088  Vector<AttributeTransferData> attributes;
1089  src_attributes.for_all(
1090  [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
1091  if (!(ATTR_DOMAIN_AS_MASK(meta_data.domain) & domain_mask)) {
1092  return true;
1093  }
1094  if (id.is_named() && skip.contains(id.name())) {
1095  return true;
1096  }
1097  if (!id.should_be_kept()) {
1098  return true;
1099  }
1100 
1101  GVArray src = src_attributes.lookup(id, meta_data.domain);
1102  BLI_assert(src);
1104  id, meta_data.domain, meta_data.data_type);
1105  BLI_assert(dst);
1106  attributes.append({std::move(src), meta_data, std::move(dst)});
1107 
1108  return true;
1109  });
1110  return attributes;
1111 }
1112 
1113 } // namespace blender::bke
1114 
const char * BKE_anonymous_attribute_id_debug_name(const AnonymousAttributeID *anonymous_id)
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_CURVE
Definition: BKE_attribute.h:31
@ ATTR_DOMAIN_INSTANCE
Definition: BKE_attribute.h:32
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
@ ATTR_DOMAIN_FACE
Definition: BKE_attribute.h:29
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
@ ATTR_DOMAIN_EDGE
Definition: BKE_attribute.h:28
eAttrDomainMask
Definition: BKE_attribute.h:36
#define ATTR_DOMAIN_AS_MASK(domain)
Definition: BKE_attribute.h:45
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_free_layer_named(struct CustomData *data, const char *name, const int totelem)
Definition: customdata.cc:2883
void CustomData_free(struct CustomData *data, int totelem)
Definition: customdata.cc:2373
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index)
Definition: customdata.cc:2831
eCDAllocType
@ CD_ASSIGN
@ CD_DUPLICATE
@ CD_DEFAULT
void * CustomData_duplicate_referenced_layer_anonymous(CustomData *data, int type, const struct AnonymousAttributeID *anonymous_id, int totelem)
void CustomData_copy(const struct CustomData *source, struct CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void * CustomData_duplicate_referenced_layer_named(struct CustomData *data, int type, const char *name, int totelem)
Definition: customdata.cc:2995
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.cc:2792
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
int CustomData_get_layer_index(const struct CustomData *data, int type)
void * CustomData_get_layer(const struct CustomData *data, int type)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
void * CustomData_add_layer_anonymous(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const struct AnonymousAttributeID *anonymous_id)
void CustomData_realloc(struct CustomData *data, int totelem)
Definition: customdata.cc:2307
void * CustomData_duplicate_referenced_layer(struct CustomData *data, int type, int totelem)
Definition: customdata.cc:2976
void CustomData_reset(struct CustomData *data)
Definition: customdata.cc:2367
void CustomData_update_typemap(struct CustomData *data)
Definition: customdata.cc:2193
support for deformation groups and hooks.
General operations for point clouds.
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED(x)
#define TIP_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
#define CD_MASK_ALL
eCustomDataType
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_COLOR
@ CD_PROP_INT8
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_PROP_BOOL
@ CD_PROP_STRING
#define MAX_NAME
Definition: DNA_defs.h:48
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
IndexRange index_range() const
Definition: BLI_array.hh:348
const CPPType & type() const
void materialize_to_uninitialized(void *dst) const
IndexRange index_range() const
static GVArray ForSingleRef(const CPPType &type, int64_t size, const void *value)
static GVArray ForSpan(GSpan span)
static GVArray ForSingle(const CPPType &type, int64_t size, const void *value)
static GVMutableArray ForSpan(GMutableSpan span)
const Value & lookup(const Key &key) const
Definition: BLI_map.hh:485
void add_new(const Key &key, const Value &value)
Definition: BLI_map.hh:220
void reserve(int64_t n)
Definition: BLI_map.hh:953
constexpr IndexRange index_range() const
Definition: BLI_span.hh:661
bool contains(const Key &key) const
Definition: BLI_set.hh:296
bool add(const Key &key)
Definition: BLI_set.hh:253
constexpr int64_t size() const
Definition: BLI_span.hh:240
void copy(char *dst, int64_t dst_size) const
constexpr bool startswith(StringRef prefix) const
void append(const T &value)
Definition: BLI_vector.hh:433
bool is_empty() const
Definition: BLI_vector.hh:706
GVArray get_varray_for_context(const GeometryComponent &component, eAttrDomain domain, IndexMask mask) const override
bool is_equal_to(const fn::FieldNode &other) const override
std::string socket_inspection_name() const override
GVArray adapt_domain(const GVArray &varray, const eAttrDomain from_domain, const eAttrDomain to_domain) const
int domain_size(const eAttrDomain domain) const
Set< AttributeIDRef > all_ids() const
std::optional< AttributeMetaData > lookup_meta_data(const AttributeIDRef &attribute_id) const
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
GVArray lookup_or_default(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const void *default_value=nullptr) const
bool for_all(const AttributeForeachCallback fn) const
const AttributeAccessorFunctions * fn_
bool is_equal_to(const fn::FieldNode &other) const override
uint64_t hash() const override
GVArray get_varray_for_context(const GeometryComponent &component, eAttrDomain domain, IndexMask mask) const override
std::string socket_inspection_name() const override
const AnonymousAttributeID & anonymous_id() const
GAttributeWriter try_get_for_write(void *owner) const final
bool try_create(void *owner, const AttributeInit &initializer) const final
bool exists(const void *owner) const final
GVArray try_get_for_read(const void *owner) const final
bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
bool try_create(void *owner, const AttributeIDRef &attribute_id, eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer) const final
bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
GAttributeReader try_get_for_read(const void *owner, const AttributeIDRef &attribute_id) const final
std::optional< blender::GSpan > get_for_read(const AttributeIDRef &attribute_id) const
bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type)
CustomDataAttributes & operator=(const CustomDataAttributes &other)
std::optional< blender::GMutableSpan > get_for_write(const AttributeIDRef &attribute_id)
bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer)
void reorder(Span< AttributeIDRef > new_order)
bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const
bool remove(const AttributeIDRef &attribute_id)
GVArray try_convert(GVArray varray, const CPPType &to_type) const
GVArray get_varray_for_context(const fn::FieldContext &context, IndexMask mask, ResourceScope &scope) const override
GVArray get_varray_for_context(const GeometryComponent &component, eAttrDomain domain, IndexMask mask) const override
bool is_equal_to(const fn::FieldNode &other) const override
std::string socket_inspection_name() const override
bool add(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
GAttributeWriter lookup_for_write(const AttributeIDRef &attribute_id)
GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
bool remove(const AttributeIDRef &attribute_id)
GAttributeWriter lookup_or_add_for_write(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefault())
GSpanAttributeWriter lookup_or_add_for_write_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefault())
GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
void foreach_domain(const FunctionRef< void(eAttrDomain)> callback) const final
GAttributeReader try_get_for_read(const void *owner, const AttributeIDRef &attribute_id) const final
bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
const AnonymousAttributeID * get() const
std::string debug_name_
Definition: FN_field.hh:254
const CPPType * type_
Definition: FN_field.hh:253
static GVArray get_index_varray(IndexMask mask)
Definition: field.cc:549
DEGForeachIDComponentCallback callback
SyclQueue void void * src
SyclQueue void void size_t num_bytes void
ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static int domain_num(const CurvesGeometry &curves, const eAttrDomain domain)
const blender::CPPType * custom_data_type_to_cpp_type(const eCustomDataType type)
Definition: customdata.cc:5312
static void * add_generic_custom_data_layer(CustomData &custom_data, const eCustomDataType data_type, const eCDAllocType alloctype, void *layer_data, const int domain_num, const AttributeIDRef &attribute_id)
static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer, const AttributeIDRef &attribute_id)
Vector< AttributeTransferData > retrieve_attributes_for_transfer(const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes, eAttrDomainMask domain_mask, const Set< std::string > &skip={})
std::ostream & operator<<(std::ostream &stream, const AssetCatalogPath &path_to_append)
const DataTypeConversions & get_implicit_type_conversions()
eAttrDomain attribute_domain_highest_priority(Span< eAttrDomain > domains)
bool allow_procedural_attribute_access(StringRef attribute_name)
const char * no_procedural_access_message
static blender::GVArray try_adapt_data_type(blender::GVArray varray, const blender::CPPType &to_type)
eCustomDataType attribute_data_type_highest_complexity(Span< eCustomDataType > data_types)
static int attribute_domain_priority(const eAttrDomain domain)
static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id, CustomData &custom_data, const eCustomDataType data_type, const int domain_num, const AttributeInit &initializer)
static StringRef get_random_id_attribute_name(const eAttrDomain domain)
static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer &layer)
eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
Definition: customdata.cc:5337
static int attribute_data_type_complexity(const eCustomDataType data_type)
static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data, const eCustomDataType data_type, const int domain_num, const AttributeInit &initializer)
static Type to_type(const eGPUType type)
vec_base< float, 3 > float3
uint64_t get_default_hash_2(const T1 &v1, const T2 &v2)
Definition: BLI_hash.hh:223
static void update(bNodeTree *ntree)
__int64 int64_t
Definition: stdint.h:89
unsigned __int64 uint64_t
Definition: stdint.h:90
const struct AnonymousAttributeID * anonymous_id
CustomDataLayer * layers
GAttributeWriter(* lookup_for_write)(void *owner, const AttributeIDRef &attribute_id)
UpdateCustomDataPointers update_custom_data_pointers