Blender  V2.93
attribute_access.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include <utility>
18 
19 #include "BKE_attribute_access.hh"
20 #include "BKE_attribute_math.hh"
21 #include "BKE_customdata.h"
22 #include "BKE_deform.h"
23 #include "BKE_geometry_set.hh"
24 #include "BKE_mesh.h"
25 #include "BKE_pointcloud.h"
26 
27 #include "DNA_mesh_types.h"
28 #include "DNA_meshdata_types.h"
29 #include "DNA_pointcloud_types.h"
30 
31 #include "BLI_color.hh"
32 #include "BLI_float2.hh"
33 #include "BLI_span.hh"
34 
35 #include "CLG_log.h"
36 
37 #include "NOD_type_conversions.hh"
38 
40 
41 static CLG_LogRef LOG = {"bke.attribute_access"};
42 
43 using blender::float3;
44 using blender::Set;
45 using blender::StringRef;
50 
51 namespace blender::bke {
52 
53 /* -------------------------------------------------------------------- */
58 {
59  if (array_is_temporary_ && array_buffer_ != nullptr) {
62  }
63 }
64 
66 {
67  if (size_ == 0) {
68  return fn::GSpan(cpp_type_);
69  }
70  if (array_buffer_ == nullptr) {
71  std::lock_guard lock{span_mutex_};
72  if (array_buffer_ == nullptr) {
73  this->initialize_span();
74  }
75  }
77 }
78 
80 {
81  const int element_size = cpp_type_.size();
82  array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
83  array_is_temporary_ = true;
84  for (const int i : IndexRange(size_)) {
85  this->get_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
86  }
87 }
88 
90 {
92  CLOG_ERROR(&LOG, "Forgot to call apply_span.");
93  }
94  if (array_is_temporary_ && array_buffer_ != nullptr) {
97  }
98 }
99 
104 {
105  if (size_ == 0) {
106  return fn::GMutableSpan(cpp_type_);
107  }
108  if (array_buffer_ == nullptr) {
109  this->initialize_span(false);
110  }
113 }
114 
116 {
117  if (size_ == 0) {
118  return fn::GMutableSpan(cpp_type_);
119  }
120  if (array_buffer_ == nullptr) {
121  this->initialize_span(true);
122  }
125 }
126 
127 void WriteAttribute::initialize_span(const bool write_only)
128 {
129  const int element_size = cpp_type_.size();
130  array_buffer_ = MEM_mallocN_aligned(element_size * size_, cpp_type_.alignment(), __func__);
131  array_is_temporary_ = true;
132  if (write_only) {
133  /* This does nothing for trivial types, but is necessary for general correctness. */
135  }
136  else {
137  for (const int i : IndexRange(size_)) {
138  this->get(i, POINTER_OFFSET(array_buffer_, i * element_size));
139  }
140  }
141 }
142 
144 {
145  this->apply_span_if_necessary();
146  array_should_be_applied_ = false;
147 }
148 
150 {
151  /* Only works when the span has been initialized beforehand. */
152  BLI_assert(array_buffer_ != nullptr);
153 
154  const int element_size = cpp_type_.size();
155  for (const int i : IndexRange(size_)) {
156  this->set_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
157  }
158 }
159 
160 /* This is used by the #OutputAttributePtr class. */
162  public:
165  std::string final_name;
166 
170  std::string final_name)
172  data(data),
174  final_name(std::move(final_name))
175  {
176  }
177 
179  {
180  if (data.data() != nullptr) {
182  MEM_freeN(data.data());
183  }
184  }
185 
186  void get_internal(const int64_t index, void *r_value) const override
187  {
188  data.type().copy_to_uninitialized(data[index], r_value);
189  }
190 
191  void set_internal(const int64_t index, const void *value) override
192  {
193  data.type().copy_to_initialized(value, data[index]);
194  }
195 
196  void initialize_span(const bool UNUSED(write_only)) override
197  {
198  array_buffer_ = data.data();
199  array_is_temporary_ = false;
200  }
201 
202  void apply_span_if_necessary() override
203  {
204  /* Do nothing, because the span contains the attribute itself already. */
205  }
206 };
207 
209  private:
210  const CPPType &from_type_;
211  const CPPType &to_type_;
212  ReadAttributePtr base_attribute_;
213  void (*convert_)(const void *src, void *dst);
214 
215  public:
216  ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
217  : ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()),
218  from_type_(base_attribute->cpp_type()),
219  to_type_(to_type),
220  base_attribute_(std::move(base_attribute))
221  {
223  convert_ = conversions.get_conversion_functions(base_attribute_->cpp_type(), to_type)
225  }
226 
227  void get_internal(const int64_t index, void *r_value) const override
228  {
229  BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
230  base_attribute_->get(index, buffer);
231  convert_(buffer, r_value);
232  }
233 };
234 
238 {
239  switch (type) {
240  case CD_PROP_FLOAT:
241  return &CPPType::get<float>();
242  case CD_PROP_FLOAT2:
243  return &CPPType::get<float2>();
244  case CD_PROP_FLOAT3:
245  return &CPPType::get<float3>();
246  case CD_PROP_INT32:
247  return &CPPType::get<int>();
248  case CD_PROP_COLOR:
249  return &CPPType::get<Color4f>();
250  case CD_PROP_BOOL:
251  return &CPPType::get<bool>();
252  default:
253  return nullptr;
254  }
255  return nullptr;
256 }
257 
259 {
260  if (type.is<float>()) {
261  return CD_PROP_FLOAT;
262  }
263  if (type.is<float2>()) {
264  return CD_PROP_FLOAT2;
265  }
266  if (type.is<float3>()) {
267  return CD_PROP_FLOAT3;
268  }
269  if (type.is<int>()) {
270  return CD_PROP_INT32;
271  }
272  if (type.is<Color4f>()) {
273  return CD_PROP_COLOR;
274  }
275  if (type.is<bool>()) {
276  return CD_PROP_BOOL;
277  }
278  return static_cast<CustomDataType>(-1);
279 }
280 
282 {
283  switch (data_type) {
284  case CD_PROP_BOOL:
285  return 0;
286  case CD_PROP_INT32:
287  return 1;
288  case CD_PROP_FLOAT:
289  return 2;
290  case CD_PROP_FLOAT2:
291  return 3;
292  case CD_PROP_FLOAT3:
293  return 4;
294  case CD_PROP_COLOR:
295  return 5;
296 #if 0 /* These attribute types are not supported yet. */
297  case CD_MLOOPCOL:
298  return 3;
299  case CD_PROP_STRING:
300  return 6;
301 #endif
302  default:
303  /* Only accept "generic" custom data types used by the attribute system. */
305  return 0;
306  }
307 }
308 
310 {
311  int highest_complexity = INT_MIN;
312  CustomDataType most_complex_type = CD_PROP_COLOR;
313 
314  for (const CustomDataType data_type : data_types) {
315  const int complexity = attribute_data_type_complexity(data_type);
316  if (complexity > highest_complexity) {
317  highest_complexity = complexity;
318  most_complex_type = data_type;
319  }
320  }
321 
322  return most_complex_type;
323 }
324 
330 {
331  switch (domain) {
332 #if 0
333  case ATTR_DOMAIN_CURVE:
334  return 0;
335 #endif
336  case ATTR_DOMAIN_FACE:
337  return 1;
338  case ATTR_DOMAIN_EDGE:
339  return 2;
340  case ATTR_DOMAIN_POINT:
341  return 3;
342  case ATTR_DOMAIN_CORNER:
343  return 4;
344  default:
345  /* Domain not supported in nodes yet. */
347  return 0;
348  }
349 }
350 
356 {
357  int highest_priority = INT_MIN;
358  AttributeDomain highest_priority_domain = ATTR_DOMAIN_CORNER;
359 
360  for (const AttributeDomain domain : domains) {
361  const int priority = attribute_domain_priority(domain);
362  if (priority > highest_priority) {
363  highest_priority = priority;
364  highest_priority_domain = domain;
365  }
366  }
367 
368  return highest_priority_domain;
369 }
370 
372  const GeometryComponent &component) const
373 {
374  const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
375  if (custom_data == nullptr) {
376  return {};
377  }
378 
379  const int domain_size = component.attribute_domain_size(domain_);
380  const void *data = CustomData_get_layer(custom_data, stored_type_);
381  if (data == nullptr) {
382  return {};
383  }
384  return as_read_attribute_(data, domain_size);
385 }
386 
389 {
390  if (writable_ != Writable) {
391  return {};
392  }
393  CustomData *custom_data = custom_data_access_.get_custom_data(component);
394  if (custom_data == nullptr) {
395  return {};
396  }
397  const int domain_size = component.attribute_domain_size(domain_);
398  void *data = CustomData_get_layer(custom_data, stored_type_);
399  if (data == nullptr) {
400  return {};
401  }
402  void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size);
403  if (data != new_data) {
404  custom_data_access_.update_custom_data_pointers(component);
405  data = new_data;
406  }
407  if (update_on_write_ != nullptr) {
408  update_on_write_(component);
409  }
410  return as_write_attribute_(data, domain_size);
411 }
412 
414 {
415  if (deletable_ != Deletable) {
416  return false;
417  }
418  CustomData *custom_data = custom_data_access_.get_custom_data(component);
419  if (custom_data == nullptr) {
420  return {};
421  }
422 
423  const int domain_size = component.attribute_domain_size(domain_);
424  const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
425  const bool delete_success = CustomData_free_layer(
426  custom_data, stored_type_, domain_size, layer_index);
427  if (delete_success) {
428  custom_data_access_.update_custom_data_pointers(component);
429  }
430  return delete_success;
431 }
432 
434 {
435  if (createable_ != Creatable) {
436  return false;
437  }
438  CustomData *custom_data = custom_data_access_.get_custom_data(component);
439  if (custom_data == nullptr) {
440  return false;
441  }
442  if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
443  /* Exists already. */
444  return false;
445  }
446  const int domain_size = component.attribute_domain_size(domain_);
447  const void *data = CustomData_add_layer(
448  custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size);
449  const bool success = data != nullptr;
450  if (success) {
451  custom_data_access_.update_custom_data_pointers(component);
452  }
453  return success;
454 }
455 
457 {
458  const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
459  if (custom_data == nullptr) {
460  return false;
461  }
462  const void *data = CustomData_get_layer(custom_data, stored_type_);
463  return data != nullptr;
464 }
465 
467  const GeometryComponent &component, const StringRef attribute_name) const
468 {
469  const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
470  if (custom_data == nullptr) {
471  return {};
472  }
473  const int domain_size = component.attribute_domain_size(domain_);
474  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
475  if (layer.name != attribute_name) {
476  continue;
477  }
478  const CustomDataType data_type = (CustomDataType)layer.type;
479  switch (data_type) {
480  case CD_PROP_FLOAT:
481  return this->layer_to_read_attribute<float>(layer, domain_size);
482  case CD_PROP_FLOAT2:
483  return this->layer_to_read_attribute<float2>(layer, domain_size);
484  case CD_PROP_FLOAT3:
485  return this->layer_to_read_attribute<float3>(layer, domain_size);
486  case CD_PROP_INT32:
487  return this->layer_to_read_attribute<int>(layer, domain_size);
488  case CD_PROP_COLOR:
489  return this->layer_to_read_attribute<Color4f>(layer, domain_size);
490  case CD_PROP_BOOL:
491  return this->layer_to_read_attribute<bool>(layer, domain_size);
492  default:
493  break;
494  }
495  }
496  return {};
497 }
498 
500  GeometryComponent &component, const StringRef attribute_name) const
501 {
502  CustomData *custom_data = custom_data_access_.get_custom_data(component);
503  if (custom_data == nullptr) {
504  return {};
505  }
506  const int domain_size = component.attribute_domain_size(domain_);
507  for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
508  if (layer.name != attribute_name) {
509  continue;
510  }
511  CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_size);
512  const CustomDataType data_type = (CustomDataType)layer.type;
513  switch (data_type) {
514  case CD_PROP_FLOAT:
515  return this->layer_to_write_attribute<float>(layer, domain_size);
516  case CD_PROP_FLOAT2:
517  return this->layer_to_write_attribute<float2>(layer, domain_size);
518  case CD_PROP_FLOAT3:
519  return this->layer_to_write_attribute<float3>(layer, domain_size);
520  case CD_PROP_INT32:
521  return this->layer_to_write_attribute<int>(layer, domain_size);
522  case CD_PROP_COLOR:
523  return this->layer_to_write_attribute<Color4f>(layer, domain_size);
524  case CD_PROP_BOOL:
525  return this->layer_to_write_attribute<bool>(layer, domain_size);
526  default:
527  break;
528  }
529  }
530  return {};
531 }
532 
534  const StringRef attribute_name) const
535 {
536  CustomData *custom_data = custom_data_access_.get_custom_data(component);
537  if (custom_data == nullptr) {
538  return false;
539  }
540  const int domain_size = component.attribute_domain_size(domain_);
541  for (const int i : IndexRange(custom_data->totlayer)) {
542  const CustomDataLayer &layer = custom_data->layers[i];
543  if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) {
544  CustomData_free_layer(custom_data, layer.type, domain_size, i);
545  return true;
546  }
547  }
548  return false;
549 }
550 
552  const StringRef attribute_name,
553  const AttributeDomain domain,
554  const CustomDataType data_type) const
555 {
556  if (domain_ != domain) {
557  return false;
558  }
559  if (!this->type_is_supported(data_type)) {
560  return false;
561  }
562  CustomData *custom_data = custom_data_access_.get_custom_data(component);
563  if (custom_data == nullptr) {
564  return false;
565  }
566  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
567  if (layer.name == attribute_name) {
568  return false;
569  }
570  }
571  const int domain_size = component.attribute_domain_size(domain_);
572  char attribute_name_c[MAX_NAME];
573  attribute_name.copy(attribute_name_c);
575  custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
576  return true;
577 }
578 
581 {
582  const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
583  if (custom_data == nullptr) {
584  return true;
585  }
586  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
587  const CustomDataType data_type = (CustomDataType)layer.type;
588  if (this->type_is_supported(data_type)) {
589  AttributeMetaData meta_data{domain_, data_type};
590  if (!callback(layer.name, meta_data)) {
591  return false;
592  }
593  }
594  }
595  return true;
596 }
597 
599  const GeometryComponent &component, const StringRef attribute_name) const
600 {
601  const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
602  if (custom_data == nullptr) {
603  return {};
604  }
605  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
606  if (layer.type == stored_type_) {
607  if (layer.name == attribute_name) {
608  const int domain_size = component.attribute_domain_size(domain_);
609  return as_read_attribute_(layer.data, domain_size);
610  }
611  }
612  }
613  return {};
614 }
615 
617  GeometryComponent &component, const StringRef attribute_name) const
618 {
619  CustomData *custom_data = custom_data_access_.get_custom_data(component);
620  if (custom_data == nullptr) {
621  return {};
622  }
623  for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
624  if (layer.type == stored_type_) {
625  if (layer.name == attribute_name) {
626  const int domain_size = component.attribute_domain_size(domain_);
627  void *data_old = layer.data;
629  custom_data, stored_type_, layer.name, domain_size);
630  if (data_old != data_new) {
631  custom_data_access_.update_custom_data_pointers(component);
632  }
633  return as_write_attribute_(layer.data, domain_size);
634  }
635  }
636  }
637  return {};
638 }
639 
641  const StringRef attribute_name) const
642 {
643  CustomData *custom_data = custom_data_access_.get_custom_data(component);
644  if (custom_data == nullptr) {
645  return false;
646  }
647  for (const int i : IndexRange(custom_data->totlayer)) {
648  const CustomDataLayer &layer = custom_data->layers[i];
649  if (layer.type == stored_type_) {
650  if (layer.name == attribute_name) {
651  const int domain_size = component.attribute_domain_size(domain_);
652  CustomData_free_layer(custom_data, stored_type_, domain_size, i);
653  custom_data_access_.update_custom_data_pointers(component);
654  return true;
655  }
656  }
657  }
658  return false;
659 }
660 
663 {
664  const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
665  if (custom_data == nullptr) {
666  return true;
667  }
668  for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
669  if (layer.type == stored_type_) {
670  AttributeMetaData meta_data{domain_, attribute_type_};
671  if (!callback(layer.name, meta_data)) {
672  return false;
673  }
674  }
675  }
676  return true;
677 }
678 
680  const FunctionRef<void(AttributeDomain)> callback) const
681 {
682  callback(domain_);
683 }
684 
685 } // namespace blender::bke
686 
687 /* -------------------------------------------------------------------- */
691 const blender::bke::ComponentAttributeProviders *GeometryComponent::get_attribute_providers() const
692 {
693  return nullptr;
694 }
695 
697 {
698  using namespace blender::bke;
699  const ComponentAttributeProviders *providers = this->get_attribute_providers();
700  if (providers == nullptr) {
701  return false;
702  }
703  return providers->supported_domains().contains(domain);
704 }
705 
707 {
708  return 0;
709 }
710 
712  const StringRef attribute_name) const
713 {
714  using namespace blender::bke;
715  const ComponentAttributeProviders *providers = this->get_attribute_providers();
716  if (providers == nullptr) {
717  return {};
718  }
719  const BuiltinAttributeProvider *builtin_provider =
720  providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
721  if (builtin_provider != nullptr) {
722  return builtin_provider->try_get_for_read(*this);
723  }
724  for (const DynamicAttributesProvider *dynamic_provider :
725  providers->dynamic_attribute_providers()) {
726  ReadAttributePtr attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
727  if (attribute) {
728  return attribute;
729  }
730  }
731  return {};
732 }
733 
735  ReadAttributePtr attribute, const AttributeDomain new_domain) const
736 {
737  if (attribute && attribute->domain() == new_domain) {
738  return attribute;
739  }
740  return {};
741 }
742 
744 {
745  using namespace blender::bke;
746  const ComponentAttributeProviders *providers = this->get_attribute_providers();
747  if (providers == nullptr) {
748  return {};
749  }
750  const BuiltinAttributeProvider *builtin_provider =
751  providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
752  if (builtin_provider != nullptr) {
753  return builtin_provider->try_get_for_write(*this);
754  }
755  for (const DynamicAttributesProvider *dynamic_provider :
756  providers->dynamic_attribute_providers()) {
757  WriteAttributePtr attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
758  if (attribute) {
759  return attribute;
760  }
761  }
762  return {};
763 }
764 
766 {
767  using namespace blender::bke;
768  const ComponentAttributeProviders *providers = this->get_attribute_providers();
769  if (providers == nullptr) {
770  return {};
771  }
772  const BuiltinAttributeProvider *builtin_provider =
773  providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
774  if (builtin_provider != nullptr) {
775  return builtin_provider->try_delete(*this);
776  }
777  bool success = false;
778  for (const DynamicAttributesProvider *dynamic_provider :
779  providers->dynamic_attribute_providers()) {
780  success = dynamic_provider->try_delete(*this, attribute_name) || success;
781  }
782  return success;
783 }
784 
786  const AttributeDomain domain,
787  const CustomDataType data_type)
788 {
789  using namespace blender::bke;
790  if (attribute_name.is_empty()) {
791  return false;
792  }
793  const ComponentAttributeProviders *providers = this->get_attribute_providers();
794  if (providers == nullptr) {
795  return false;
796  }
797  const BuiltinAttributeProvider *builtin_provider =
798  providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
799  if (builtin_provider != nullptr) {
800  if (builtin_provider->domain() != domain) {
801  return false;
802  }
803  if (builtin_provider->data_type() != data_type) {
804  return false;
805  }
806  return builtin_provider->try_create(*this);
807  }
808  for (const DynamicAttributesProvider *dynamic_provider :
809  providers->dynamic_attribute_providers()) {
810  if (dynamic_provider->try_create(*this, attribute_name, domain, data_type)) {
811  return true;
812  }
813  }
814  return false;
815 }
816 
818 {
819  Set<std::string> attributes;
820  this->attribute_foreach([&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) {
821  attributes.add(name);
822  return true;
823  });
824  return attributes;
825 }
826 
832 {
833  using namespace blender::bke;
834  const ComponentAttributeProviders *providers = this->get_attribute_providers();
835  if (providers == nullptr) {
836  return true;
837  }
838 
839  /* Keep track handled attribute names to make sure that we do not return the same name twice. */
840  Set<std::string> handled_attribute_names;
841 
842  for (const BuiltinAttributeProvider *provider :
843  providers->builtin_attribute_providers().values()) {
844  if (provider->exists(*this)) {
845  AttributeMetaData meta_data{provider->domain(), provider->data_type()};
846  if (!callback(provider->name(), meta_data)) {
847  return false;
848  }
849  handled_attribute_names.add_new(provider->name());
850  }
851  }
852  for (const DynamicAttributesProvider *provider : providers->dynamic_attribute_providers()) {
853  const bool continue_loop = provider->foreach_attribute(
854  *this, [&](StringRefNull name, const AttributeMetaData &meta_data) {
855  if (handled_attribute_names.add(name)) {
856  return callback(name, meta_data);
857  }
858  return true;
859  });
860  if (!continue_loop) {
861  return false;
862  }
863  }
864 
865  return true;
866 }
867 
869 {
870  ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
871  if (attribute) {
872  return true;
873  }
874  return false;
875 }
876 
878  const blender::fn::CPPType &to_type)
879 {
880  const blender::fn::CPPType &from_type = attribute->cpp_type();
881  if (from_type == to_type) {
882  return attribute;
883  }
884 
885  const blender::nodes::DataTypeConversions &conversions =
887  if (!conversions.is_convertible(from_type, to_type)) {
888  return {};
889  }
890 
891  return std::make_unique<blender::bke::ConvertedReadAttribute>(std::move(attribute), to_type);
892 }
893 
895  const StringRef attribute_name,
896  const AttributeDomain domain,
897  const CustomDataType data_type) const
898 {
899  ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
900  if (!attribute) {
901  return {};
902  }
903 
904  if (domain != ATTR_DOMAIN_AUTO && attribute->domain() != domain) {
905  attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
906  if (!attribute) {
907  return {};
908  }
909  }
910 
912  BLI_assert(cpp_type != nullptr);
913  if (attribute->cpp_type() != *cpp_type) {
914  attribute = try_adapt_data_type(std::move(attribute), *cpp_type);
915  if (!attribute) {
916  return {};
917  }
918  }
919 
920  return attribute;
921 }
922 
924  const AttributeDomain domain) const
925 {
926  if (!this->attribute_domain_supported(domain)) {
927  return {};
928  }
929 
930  ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
931  if (!attribute) {
932  return {};
933  }
934 
935  if (attribute->domain() != domain) {
936  attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
937  if (!attribute) {
938  return {};
939  }
940  }
941 
942  return attribute;
943 }
944 
946  const AttributeDomain domain,
947  const CustomDataType data_type,
948  const void *default_value) const
949 {
950  ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name, domain, data_type);
951  if (attribute) {
952  return attribute;
953  }
954  return this->attribute_get_constant_for_read(domain, data_type, default_value);
955 }
956 
958  const AttributeDomain domain, const CustomDataType data_type, const void *value) const
959 {
960  BLI_assert(this->attribute_domain_supported(domain));
962  BLI_assert(cpp_type != nullptr);
963  if (value == nullptr) {
964  value = cpp_type->default_value();
965  }
966  const int domain_size = this->attribute_domain_size(domain);
967  return std::make_unique<blender::bke::ConstantReadAttribute>(
968  domain, domain_size, *cpp_type, value);
969 }
970 
972  const AttributeDomain domain,
973  const CustomDataType in_data_type,
974  const CustomDataType out_data_type,
975  const void *value) const
976 {
977  BLI_assert(this->attribute_domain_supported(domain));
978  if (value == nullptr || in_data_type == out_data_type) {
979  return this->attribute_get_constant_for_read(domain, out_data_type, value);
980  }
981 
983  in_data_type);
985  out_data_type);
986  BLI_assert(in_cpp_type != nullptr);
987  BLI_assert(out_cpp_type != nullptr);
988 
989  const blender::nodes::DataTypeConversions &conversions =
991  BLI_assert(conversions.is_convertible(*in_cpp_type, *out_cpp_type));
992 
993  void *out_value = alloca(out_cpp_type->size());
994  conversions.convert_to_uninitialized(*in_cpp_type, *out_cpp_type, value, out_value);
995 
996  const int domain_size = this->attribute_domain_size(domain);
997  blender::bke::ReadAttributePtr attribute = std::make_unique<blender::bke::ConstantReadAttribute>(
998  domain, domain_size, *out_cpp_type, out_value);
999 
1000  out_cpp_type->destruct(out_value);
1001  return attribute;
1002 }
1003 
1005  const AttributeDomain domain,
1006  const CustomDataType data_type,
1007  const void *default_value)
1008 {
1010  BLI_assert(cpp_type != nullptr);
1011 
1012  WriteAttributePtr attribute = this->attribute_try_get_for_write(attribute_name);
1013 
1014  /* If the attribute doesn't exist, make a new one with the correct type. */
1015  if (!attribute) {
1016  this->attribute_try_create(attribute_name, domain, data_type);
1017  attribute = this->attribute_try_get_for_write(attribute_name);
1018  if (attribute && default_value != nullptr) {
1019  void *data = attribute->get_span_for_write_only().data();
1020  cpp_type->fill_initialized(default_value, data, attribute->size());
1021  attribute->apply_span();
1022  }
1023  return OutputAttributePtr(std::move(attribute));
1024  }
1025 
1026  /* If an existing attribute has a matching domain and type, just use that. */
1027  if (attribute->domain() == domain && attribute->cpp_type() == *cpp_type) {
1028  return OutputAttributePtr(std::move(attribute));
1029  }
1030 
1031  /* Otherwise create a temporary buffer to use before saving the new attribute. */
1032  return OutputAttributePtr(*this, domain, attribute_name, data_type);
1033 }
1034 
1035 /* Construct from an attribute that already exists in the geometry component. */
1037  : attribute_(std::move(attribute))
1038 {
1039 }
1040 
1041 /* Construct a temporary attribute that has to replace an existing one later on. */
1043  AttributeDomain domain,
1044  std::string final_name,
1045  CustomDataType data_type)
1046 {
1048  BLI_assert(cpp_type != nullptr);
1049 
1050  const int domain_size = component.attribute_domain_size(domain);
1051  void *buffer = MEM_malloc_arrayN(domain_size, cpp_type->size(), __func__);
1052  GMutableSpan new_span{*cpp_type, buffer, domain_size};
1053 
1054  /* Copy converted values from conflicting attribute, in case the value is read.
1055  * TODO: An optimization could be to not do this, when the caller says that the attribute will
1056  * only be written. */
1057  ReadAttributePtr src_attribute = component.attribute_get_for_read(
1058  final_name, domain, data_type, nullptr);
1059  for (const int i : blender::IndexRange(domain_size)) {
1060  src_attribute->get(i, new_span[i]);
1061  }
1062 
1063  attribute_ = std::make_unique<blender::bke::TemporaryWriteAttribute>(
1064  domain, new_span, component, std::move(final_name));
1065 }
1066 
1067 /* Store the computed attribute. If it was stored from the beginning already, nothing is done. This
1068  * might delete another attribute with the same name. */
1070 {
1071  if (!attribute_) {
1072  CLOG_WARN(&LOG, "Trying to save an attribute that does not exist anymore.");
1073  return;
1074  }
1075 
1077  dynamic_cast<blender::bke::TemporaryWriteAttribute *>(attribute_.get());
1078 
1079  if (attribute == nullptr) {
1080  /* The attribute is saved already. */
1081  attribute_.reset();
1082  return;
1083  }
1084 
1085  StringRefNull name = attribute->final_name;
1086  const blender::fn::CPPType &cpp_type = attribute->cpp_type();
1087 
1088  /* Delete an existing attribute with the same name if necessary. */
1089  attribute->component.attribute_try_delete(name);
1090 
1091  if (!attribute->component.attribute_try_create(
1092  name, attribute_->domain(), attribute_->custom_data_type())) {
1093  /* Cannot create the target attribute for some reason. */
1094  CLOG_WARN(&LOG,
1095  "Creating the '%s' attribute with type '%s' failed.",
1096  name.c_str(),
1097  cpp_type.name().c_str());
1098  attribute_.reset();
1099  return;
1100  }
1101 
1102  WriteAttributePtr new_attribute = attribute->component.attribute_try_get_for_write(name);
1103 
1104  GMutableSpan temp_span = attribute->data;
1105  GMutableSpan new_span = new_attribute->get_span_for_write_only();
1106  BLI_assert(temp_span.size() == new_span.size());
1107 
1108  /* Currently we copy over the attribute. In the future we want to reuse the buffer. */
1109  cpp_type.move_to_initialized_n(temp_span.data(), new_span.data(), new_span.size());
1110  new_attribute->apply_span();
1111 
1112  attribute_.reset();
1113 }
1114 
1116 {
1117  if (attribute_) {
1118  CLOG_ERROR(&LOG, "Forgot to call #save or #apply_span_and_save.");
1119  }
1120 }
1121 
1122 /* Utility function to call #apply_span and #save in the right order. */
1124 {
1125  BLI_assert(attribute_);
1126  attribute_->apply_span();
1127  this->save();
1128 }
1129 
AttributeDomain
Definition: BKE_attribute.h:41
@ ATTR_DOMAIN_CURVE
Definition: BKE_attribute.h:47
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
@ ATTR_DOMAIN_FACE
Definition: BKE_attribute.h:46
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:45
@ ATTR_DOMAIN_AUTO
Definition: BKE_attribute.h:42
@ ATTR_DOMAIN_EDGE
Definition: BKE_attribute.h:44
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index)
Definition: customdata.c:2655
@ CD_DEFAULT
void * CustomData_duplicate_referenced_layer_named(struct CustomData *data, const int type, const char *name, const int totelem)
Definition: customdata.c:2807
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.c:2637
void * CustomData_duplicate_referenced_layer(struct CustomData *data, const int type, const int totelem)
Definition: customdata.c:2788
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.c:2620
support for deformation groups and hooks.
General operations for point-clouds.
#define BLI_assert_unreachable()
Definition: BLI_assert.h:96
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define final(a, b, c)
Definition: BLI_hash.h:35
#define UNUSED(x)
#define POINTER_OFFSET(v, ofs)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:204
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:203
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:126
CustomDataType
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_COLOR
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_PROP_BOOL
@ CD_MLOOPCOL
@ CD_PROP_STRING
#define MAX_NAME
Definition: DNA_defs.h:62
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
Definition: FN_cpp_type.hh:676
_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
static ReadAttributePtr try_adapt_data_type(ReadAttributePtr attribute, const blender::fn::CPPType &to_type)
static CLG_LogRef LOG
virtual blender::bke::ReadAttributePtr attribute_try_adapt_domain(blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const
virtual int attribute_domain_size(const AttributeDomain domain) const
blender::bke::WriteAttributePtr attribute_try_get_for_write(const blender::StringRef attribute_name)
bool attribute_exists(const blender::StringRef attribute_name) const
blender::bke::ReadAttributePtr attribute_get_constant_for_read(const AttributeDomain domain, const CustomDataType data_type, const void *value) const
blender::Set< std::string > attribute_names() const
bool attribute_try_delete(const blender::StringRef attribute_name)
blender::bke::ReadAttributePtr attribute_try_get_for_read(const blender::StringRef attribute_name) const
OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type, const void *default_value=nullptr)
bool attribute_foreach(const AttributeForeachCallback callback) const
blender::bke::ReadAttributePtr attribute_get_constant_for_read_converted(const AttributeDomain domain, const CustomDataType in_data_type, const CustomDataType out_data_type, const void *value) const
blender::bke::ReadAttributePtr attribute_get_for_read(const blender::StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type, const void *default_value) const
bool attribute_try_create(const blender::StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type)
bool attribute_domain_supported(const AttributeDomain domain) const
OutputAttributePtr()=default
bool add(const Key &key)
Definition: BLI_set.hh:267
void add_new(const Key &key)
Definition: BLI_set.hh:252
constexpr bool is_empty() const
void copy(char *dst, const int64_t dst_size) const
constexpr const char * c_str() const
virtual bool try_create(GeometryComponent &UNUSED(component)) const =0
virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const =0
virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const =0
virtual bool try_delete(GeometryComponent &component) const =0
bool exists(const GeometryComponent &component) const final
WriteAttributePtr try_get_for_write(GeometryComponent &component) const final
bool try_create(GeometryComponent &component) const final
bool try_delete(GeometryComponent &component) const final
ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final
Span< const DynamicAttributesProvider * > dynamic_attribute_providers() const
const Map< std::string, const BuiltinAttributeProvider * > & builtin_attribute_providers() const
Span< AttributeDomain > supported_domains() const
void get_internal(const int64_t index, void *r_value) const override
ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
WriteAttributePtr try_get_for_write(GeometryComponent &component, const StringRef attribute_name) const final
ReadAttributePtr try_get_for_read(const GeometryComponent &component, const StringRef attribute_name) const final
bool foreach_attribute(const GeometryComponent &component, const AttributeForeachCallback callback) const final
bool try_create(GeometryComponent &component, const StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type) const final
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
ReadAttributePtr try_get_for_read(const GeometryComponent &component, const StringRef attribute_name) const final
void foreach_domain(const FunctionRef< void(AttributeDomain)> callback) const final
WriteAttributePtr try_get_for_write(GeometryComponent &component, const StringRef attribute_name) const final
bool foreach_attribute(const GeometryComponent &component, const AttributeForeachCallback callback) const final
virtual void get_internal(const int64_t index, void *r_value) const =0
virtual void initialize_span() const
const CPPType & cpp_type() const
AttributeDomain domain() const
void set_internal(const int64_t index, const void *value) override
TemporaryWriteAttribute(AttributeDomain domain, GMutableSpan data, GeometryComponent &component, std::string final_name)
void initialize_span(const bool UNUSED(write_only)) override
void get_internal(const int64_t index, void *r_value) const override
AttributeDomain domain() const
virtual void set_internal(const int64_t index, const void *value)=0
void get(const int64_t index, void *r_value) const
virtual void initialize_span(const bool write_only)
fn::GMutableSpan get_span_for_write_only()
const CPPType & cpp_type() const
int64_t size() const
Definition: FN_cpp_type.hh:280
StringRefNull name() const
Definition: FN_cpp_type.hh:269
int64_t alignment() const
Definition: FN_cpp_type.hh:291
void fill_initialized(const void *value, void *dst, int64_t n) const
Definition: FN_cpp_type.hh:597
void construct_default_n(void *ptr, int64_t n) const
Definition: FN_cpp_type.hh:336
void destruct(void *ptr) const
Definition: FN_cpp_type.hh:358
void copy_to_initialized(const void *src, void *dst) const
Definition: FN_cpp_type.hh:390
void destruct_n(void *ptr, int64_t n) const
Definition: FN_cpp_type.hh:365
void copy_to_uninitialized(const void *src, void *dst) const
Definition: FN_cpp_type.hh:425
const void * default_value() const
Definition: FN_cpp_type.hh:657
void move_to_initialized_n(void *src, void *dst, int64_t n) const
Definition: FN_cpp_type.hh:469
const CPPType & type() const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
void convert_to_uninitialized(const CPPType &from_type, const CPPType &to_type, const void *from_value, void *to_value) const
const ConversionFunctions * get_conversion_functions(fn::MFDataType from, fn::MFDataType to) const
DEGForeachIDComponentCallback callback
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN_aligned)(size_t len, size_t alignment, const char *str)
Definition: mallocn.c:49
CustomDataType cpp_type_to_custom_data_type(const CPPType &type)
AttributeDomain attribute_domain_highest_priority(Span< AttributeDomain > domains)
static int attribute_domain_priority(const AttributeDomain domain)
static int attribute_data_type_complexity(const CustomDataType data_type)
std::unique_ptr< WriteAttribute > WriteAttributePtr
const CPPType * custom_data_type_to_cpp_type(const CustomDataType type)
std::unique_ptr< ReadAttribute > ReadAttributePtr
CustomDataType attribute_data_type_highest_complexity(Span< CustomDataType > data_types)
const DataTypeConversions & get_implicit_type_conversions()
__int64 int64_t
Definition: stdint.h:92
AttributeDomain domain
CustomDataLayer * layers
UpdateCustomDataPointers update_custom_data_pointers
void(* convert_single_to_uninitialized)(const void *src, void *dst)