Blender  V3.3
geometry_component_curve.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_task.hh"
4 
5 #include "DNA_ID_enums.h"
6 #include "DNA_curve_types.h"
7 
8 #include "BKE_attribute_math.hh"
9 #include "BKE_curve.h"
10 #include "BKE_geometry_set.hh"
11 #include "BKE_lib_id.h"
12 #include "BKE_spline.hh"
13 
15 
17 using blender::GSpan;
18 using blender::GVArray;
20 
21 /* -------------------------------------------------------------------- */
26 {
27 }
28 
30 {
31  this->clear();
32 }
33 
35 {
36  CurveComponentLegacy *new_component = new CurveComponentLegacy();
37  if (curve_ != nullptr) {
38  new_component->curve_ = new CurveEval(*curve_);
39  new_component->ownership_ = GeometryOwnershipType::Owned;
40  }
41  return new_component;
42 }
43 
45 {
46  BLI_assert(this->is_mutable());
47  if (curve_ != nullptr) {
48  if (ownership_ == GeometryOwnershipType::Owned) {
49  delete curve_;
50  }
51  curve_ = nullptr;
52  }
53 }
54 
56 {
57  return curve_ != nullptr;
58 }
59 
61 {
62  BLI_assert(this->is_mutable());
63  this->clear();
64  curve_ = curve;
65  ownership_ = ownership;
66 }
67 
69 {
70  BLI_assert(this->is_mutable());
71  CurveEval *curve = curve_;
72  curve_ = nullptr;
73  return curve;
74 }
75 
77 {
78  return curve_;
79 }
80 
82 {
83  BLI_assert(this->is_mutable());
84  if (ownership_ == GeometryOwnershipType::ReadOnly) {
85  curve_ = new CurveEval(*curve_);
86  ownership_ = GeometryOwnershipType::Owned;
87  }
88  return curve_;
89 }
90 
92 {
93  return curve_ == nullptr;
94 }
95 
97 {
98  return ownership_ == GeometryOwnershipType::Owned;
99 }
100 
102 {
103  BLI_assert(this->is_mutable());
104  if (ownership_ != GeometryOwnershipType::Owned) {
105  curve_ = new CurveEval(*curve_);
106  ownership_ = GeometryOwnershipType::Owned;
107  }
108 }
109 
112 /* -------------------------------------------------------------------- */
116 namespace blender::bke {
117 
118 namespace {
119 struct PointIndices {
122 };
123 } // namespace
124 static PointIndices lookup_point_indices(Span<int> offsets, const int index)
125 {
126  const int spline_index = std::upper_bound(offsets.begin(), offsets.end(), index) -
127  offsets.begin() - 1;
128  const int index_in_spline = index - offsets[spline_index];
129  return {spline_index, index_in_spline};
130 }
131 
139 template<typename T>
141  const VArray<T> &old_values,
142  MutableSpan<T> r_values)
143 {
144  const int splines_len = curve.splines().size();
145  Array<int> offsets = curve.control_point_offsets();
146  BLI_assert(r_values.size() == splines_len);
147  attribute_math::DefaultMixer<T> mixer(r_values);
148 
149  for (const int i_spline : IndexRange(splines_len)) {
150  const int spline_offset = offsets[i_spline];
151  const int spline_point_len = offsets[i_spline + 1] - spline_offset;
152  for (const int i_point : IndexRange(spline_point_len)) {
153  const T value = old_values[spline_offset + i_point];
154  mixer.mix_in(i_spline, value);
155  }
156  }
157 
158  mixer.finalize();
159 }
160 
168 template<>
170  const VArray<bool> &old_values,
171  MutableSpan<bool> r_values)
172 {
173  const int splines_len = curve.splines().size();
174  Array<int> offsets = curve.control_point_offsets();
175  BLI_assert(r_values.size() == splines_len);
176 
177  r_values.fill(true);
178 
179  for (const int i_spline : IndexRange(splines_len)) {
180  const int spline_offset = offsets[i_spline];
181  const int spline_point_len = offsets[i_spline + 1] - spline_offset;
182 
183  for (const int i_point : IndexRange(spline_point_len)) {
184  if (!old_values[spline_offset + i_point]) {
185  r_values[i_spline] = false;
186  break;
187  }
188  }
189  }
190 }
191 
193 {
194  GVArray new_varray;
195  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
196  using T = decltype(dummy);
197  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
198  Array<T> values(curve.splines().size());
199  adapt_curve_domain_point_to_spline_impl<T>(curve, varray.typed<T>(), values);
200  new_varray = VArray<T>::ForContainer(std::move(values));
201  }
202  });
203  return new_varray;
204 }
205 
211 template<typename T> class VArray_For_SplineToPoint final : public VArrayImpl<T> {
212  GVArray original_varray_;
213  /* Store existing data materialized if it was not already a span. This is expected
214  * to be worth it because a single spline's value will likely be accessed many times. */
215  VArraySpan<T> original_data_;
216  Array<int> offsets_;
217 
218  public:
219  VArray_For_SplineToPoint(GVArray original_varray, Array<int> offsets)
220  : VArrayImpl<T>(offsets.last()),
221  original_varray_(std::move(original_varray)),
222  original_data_(original_varray_.typed<T>()),
223  offsets_(std::move(offsets))
224  {
225  }
226 
227  T get(const int64_t index) const final
228  {
229  const PointIndices indices = lookup_point_indices(offsets_, index);
230  return original_data_[indices.spline_index];
231  }
232 
233  void materialize(const IndexMask mask, MutableSpan<T> r_span) const final
234  {
235  const int total_num = offsets_.last();
236  if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
237  for (const int spline_index : original_data_.index_range()) {
238  const int offset = offsets_[spline_index];
239  const int next_offset = offsets_[spline_index + 1];
240  r_span.slice(offset, next_offset - offset).fill(original_data_[spline_index]);
241  }
242  }
243  else {
244  int spline_index = 0;
245  for (const int dst_index : mask) {
246  while (offsets_[spline_index] < dst_index) {
247  spline_index++;
248  }
249  r_span[dst_index] = original_data_[spline_index];
250  }
251  }
252  }
253 
255  {
256  T *dst = r_span.data();
257  const int total_num = offsets_.last();
258  if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
259  for (const int spline_index : original_data_.index_range()) {
260  const int offset = offsets_[spline_index];
261  const int next_offset = offsets_[spline_index + 1];
262  uninitialized_fill_n(dst + offset, next_offset - offset, original_data_[spline_index]);
263  }
264  }
265  else {
266  int spline_index = 0;
267  for (const int dst_index : mask) {
268  while (offsets_[spline_index] < dst_index) {
269  spline_index++;
270  }
271  new (dst + dst_index) T(original_data_[spline_index]);
272  }
273  }
274  }
275 };
276 
278 {
279  GVArray new_varray;
280  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
281  using T = decltype(dummy);
282 
283  Array<int> offsets = curve.control_point_offsets();
284  new_varray = VArray<T>::template For<VArray_For_SplineToPoint<T>>(std::move(varray),
285  std::move(offsets));
286  });
287  return new_varray;
288 }
289 
290 } // namespace blender::bke
291 
293  const GVArray &varray,
294  const eAttrDomain from_domain,
295  const eAttrDomain to_domain)
296 {
297  if (!varray) {
298  return {};
299  }
300  if (varray.is_empty()) {
301  return {};
302  }
303  if (from_domain == to_domain) {
304  return varray;
305  }
306 
307  if (from_domain == ATTR_DOMAIN_POINT && to_domain == ATTR_DOMAIN_CURVE) {
308  return blender::bke::adapt_curve_domain_point_to_spline(curve, std::move(varray));
309  }
310  if (from_domain == ATTR_DOMAIN_CURVE && to_domain == ATTR_DOMAIN_POINT) {
311  return blender::bke::adapt_curve_domain_spline_to_point(curve, std::move(varray));
312  }
313 
314  return {};
315 }
316 
319 namespace blender::bke {
320 
321 /* -------------------------------------------------------------------- */
328  using AsReadAttribute = GVArray (*)(const CurveEval &data);
329  using AsWriteAttribute = GVMutableArray (*)(CurveEval &data);
330  const AsReadAttribute as_read_attribute_;
331  const AsWriteAttribute as_write_attribute_;
332 
333  public:
334  BuiltinSplineAttributeProvider(std::string attribute_name,
335  const eCustomDataType attribute_type,
336  const WritableEnum writable,
337  const AsReadAttribute as_read_attribute,
338  const AsWriteAttribute as_write_attribute)
339  : BuiltinAttributeProvider(std::move(attribute_name),
341  attribute_type,
343  writable,
345  as_read_attribute_(as_read_attribute),
346  as_write_attribute_(as_write_attribute)
347  {
348  }
349 
350  GVArray try_get_for_read(const void *owner) const final
351  {
352  const CurveEval *curve = static_cast<const CurveEval *>(owner);
353  if (curve == nullptr) {
354  return {};
355  }
356  return as_read_attribute_(*curve);
357  }
358 
359  GAttributeWriter try_get_for_write(void *owner) const final
360  {
361  if (writable_ != Writable) {
362  return {};
363  }
364  CurveEval *curve = static_cast<CurveEval *>(owner);
365  if (curve == nullptr) {
366  return {};
367  }
368  return {as_write_attribute_(*curve), domain_};
369  }
370 
371  bool try_delete(void *UNUSED(owner)) const final
372  {
373  return false;
374  }
375 
376  bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
377  {
378  return false;
379  }
380 
381  bool exists(const void *owner) const final
382  {
383  const CurveEval *curve = static_cast<const CurveEval *>(owner);
384  return !curve->splines().is_empty();
385  }
386 };
387 
388 static int get_spline_resolution(const SplinePtr &spline)
389 {
390  if (const BezierSpline *bezier_spline = dynamic_cast<const BezierSpline *>(spline.get())) {
391  return bezier_spline->resolution();
392  }
393  if (const NURBSpline *nurb_spline = dynamic_cast<const NURBSpline *>(spline.get())) {
394  return nurb_spline->resolution();
395  }
396  return 1;
397 }
398 
399 static void set_spline_resolution(SplinePtr &spline, const int resolution)
400 {
401  if (BezierSpline *bezier_spline = dynamic_cast<BezierSpline *>(spline.get())) {
402  bezier_spline->set_resolution(std::max(resolution, 1));
403  }
404  if (NURBSpline *nurb_spline = dynamic_cast<NURBSpline *>(spline.get())) {
405  nurb_spline->set_resolution(std::max(resolution, 1));
406  }
407 }
408 
410 {
412 }
413 
415 {
416  return VMutableArray<int>::
418 }
419 
420 static bool get_cyclic_value(const SplinePtr &spline)
421 {
422  return spline->is_cyclic();
423 }
424 
425 static void set_cyclic_value(SplinePtr &spline, const bool value)
426 {
427  if (spline->is_cyclic() != value) {
428  spline->set_cyclic(value);
429  spline->mark_cache_invalid();
430  }
431 }
432 
434 {
436 }
437 
439 {
441  curve.splines());
442 }
443 
446 /* -------------------------------------------------------------------- */
458 template<typename T>
460  Span<int> offsets,
461  const IndexMask mask,
462  MutableSpan<T> r_span)
463 {
464  const int total_num = offsets.last();
465  if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
466  for (const int spline_index : data.index_range()) {
467  const int offset = offsets[spline_index];
468  const int next_offset = offsets[spline_index + 1];
469 
471  MutableSpan<T> dst = r_span.slice(offset, next_offset - offset);
472  if (src.is_empty()) {
473  dst.fill(T());
474  }
475  else {
476  dst.copy_from(src);
477  }
478  }
479  }
480  else {
481  int spline_index = 0;
482  for (const int dst_index : mask) {
483  /* Skip splines that don't have any control points in the mask. */
484  while (dst_index >= offsets[spline_index + 1]) {
485  spline_index++;
486  }
487 
488  const int index_in_spline = dst_index - offsets[spline_index];
490  if (src.is_empty()) {
491  r_span[dst_index] = T();
492  }
493  else {
494  r_span[dst_index] = src[index_in_spline];
495  }
496  }
497  }
498 }
499 
503 template<typename T>
505  Span<int> offsets,
506  const IndexMask mask,
507  MutableSpan<T> r_span)
508 {
509  T *dst = r_span.data();
510  const int total_num = offsets.last();
511  if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
512  for (const int spline_index : data.index_range()) {
513  const int offset = offsets[spline_index];
514  const int next_offset = offsets[spline_index + 1];
515 
517  if (src.is_empty()) {
518  uninitialized_fill_n(dst + offset, next_offset - offset, T());
519  }
520  else {
521  uninitialized_copy_n(src.data(), next_offset - offset, dst + offset);
522  }
523  }
524  }
525  else {
526  int spline_index = 0;
527  for (const int dst_index : mask) {
528  /* Skip splines that don't have any control points in the mask. */
529  while (dst_index >= offsets[spline_index + 1]) {
530  spline_index++;
531  }
532 
533  const int index_in_spline = dst_index - offsets[spline_index];
535  if (src.is_empty()) {
536  new (dst + dst_index) T();
537  }
538  else {
539  new (dst + dst_index) T(src[index_in_spline]);
540  }
541  }
542  }
543 }
544 
546  const eCustomDataType data_type,
547  const Span<SplinePtr> splines)
548 {
549  switch (initializer.type) {
551  /* This function shouldn't be called in this case, since there
552  * is no need to copy anything to the new custom data array. */
554  return {};
556  return static_cast<const AttributeInitVArray &>(initializer).varray;
558  int total_num = 0;
559  for (const SplinePtr &spline : splines) {
560  total_num += spline->size();
561  }
563  static_cast<const AttributeInitMove &>(initializer).data,
564  total_num));
565  }
567  return {};
568 }
569 
571  const AttributeIDRef &attribute_id,
572  const AttributeInit &initializer,
573  const eCustomDataType data_type)
574 {
575  if (curve == nullptr || curve->splines().size() == 0) {
576  return false;
577  }
578 
579  MutableSpan<SplinePtr> splines = curve->splines();
580 
581  /* First check the one case that allows us to avoid copying the input data. */
582  if (splines.size() == 1 && initializer.type == AttributeInit::Type::MoveArray) {
583  void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
584  if (!splines.first()->attributes.create_by_move(attribute_id, data_type, source_data)) {
585  MEM_freeN(source_data);
586  return false;
587  }
588  return true;
589  }
590 
591  /* Otherwise just create a custom data layer on each of the splines. */
592  for (const int i : splines.index_range()) {
593  if (!splines[i]->attributes.create(attribute_id, data_type)) {
594  /* If attribute creation fails on one of the splines, we cannot leave the custom data
595  * layers in the previous splines around, so delete them before returning. However,
596  * this is not an expected case. */
598  return false;
599  }
600  }
601 
602  /* With a default initializer type, we can keep the values at their initial values. */
603  if (initializer.type == AttributeInit::Type::Default) {
604  return true;
605  }
606 
607  GAttributeWriter write_attribute = curve->attributes_for_write().lookup_for_write(attribute_id);
608  /* We just created the attribute, it should exist. */
609  BLI_assert(write_attribute);
610 
611  GVArray source_varray = varray_from_initializer(initializer, data_type, splines);
612  /* TODO: When we can call a variant of #set_all with a virtual array argument,
613  * this theoretically unnecessary materialize step could be removed. */
614  GVArraySpan source_VArraySpan{source_varray};
615  write_attribute.varray.set_all(source_VArraySpan.data());
616  write_attribute.finish();
617 
618  if (initializer.type == AttributeInit::Type::MoveArray) {
619  MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data);
620  }
621 
622  return true;
623 }
624 
625 static bool remove_point_attribute(CurveEval *curve, const AttributeIDRef &attribute_id)
626 {
627  if (curve == nullptr) {
628  return false;
629  }
630 
631  /* Reuse the boolean for all splines; we expect all splines to have the same attributes. */
632  bool layer_freed = false;
633  for (SplinePtr &spline : curve->splines()) {
634  layer_freed = spline->attributes.remove(attribute_id);
635  }
636  return layer_freed;
637 }
638 
642 template<typename T> class VArrayImpl_For_SplinePoints final : public VMutableArrayImpl<T> {
643  private:
644  Array<MutableSpan<T>> data_;
645  Array<int> offsets_;
646 
647  public:
649  : VMutableArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
650  {
651  }
652 
653  T get(const int64_t index) const final
654  {
655  const PointIndices indices = lookup_point_indices(offsets_, index);
656  return data_[indices.spline_index][indices.point_index];
657  }
658 
659  void set(const int64_t index, T value) final
660  {
661  const PointIndices indices = lookup_point_indices(offsets_, index);
662  data_[indices.spline_index][indices.point_index] = value;
663  }
664 
665  void set_all(Span<T> src) final
666  {
667  for (const int spline_index : data_.index_range()) {
668  const int offset = offsets_[spline_index];
669  const int next_offsets = offsets_[spline_index + 1];
670  data_[spline_index].copy_from(src.slice(offset, next_offsets - offset));
671  }
672  }
673 
674  void materialize(const IndexMask mask, MutableSpan<T> r_span) const final
675  {
676  point_attribute_materialize({(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span);
677  }
678 
680  {
682  {(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span);
683  }
684 };
685 
686 template<typename T> VArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets)
687 {
688  return VArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
689  std::move(offsets));
690 }
691 
692 template<typename T>
694 {
695  return VMutableArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
696  std::move(offsets));
697 }
698 
708  private:
709  MutableSpan<SplinePtr> splines_;
710  Array<int> offsets_;
711 
712  public:
714  : VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets))
715  {
716  }
717 
718  float3 get(const int64_t index) const final
719  {
720  const PointIndices indices = lookup_point_indices(offsets_, index);
721  return splines_[indices.spline_index]->positions()[indices.point_index];
722  }
723 
724  void set(const int64_t index, float3 value) final
725  {
726  const PointIndices indices = lookup_point_indices(offsets_, index);
727  Spline &spline = *splines_[indices.spline_index];
728  spline.positions()[indices.point_index] = value;
729  }
730 
732  {
733  for (const int spline_index : splines_.index_range()) {
734  Spline &spline = *splines_[spline_index];
735  const int offset = offsets_[spline_index];
736  const int next_offset = offsets_[spline_index + 1];
737  spline.positions().copy_from(src.slice(offset, next_offset - offset));
738  }
739  }
740 
743  {
744  Array<Span<float3>> spans(splines_.size());
745  for (const int i : spans.index_range()) {
746  spans[i] = splines_[i]->positions();
747  }
748  return spans;
749  }
750 
751  void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
752  {
753  Array<Span<float3>> spans = this->get_position_spans();
754  point_attribute_materialize(spans.as_span(), offsets_, mask, r_span);
755  }
756 
758  {
759  Array<Span<float3>> spans = this->get_position_spans();
760  point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span);
761  }
762 };
763 
765  private:
766  MutableSpan<SplinePtr> splines_;
767  Array<int> offsets_;
768  bool is_right_;
769 
770  public:
772  Array<int> offsets,
773  const bool is_right)
774  : VMutableArrayImpl<float3>(offsets.last()),
775  splines_(splines),
776  offsets_(std::move(offsets)),
777  is_right_(is_right)
778  {
779  }
780 
781  float3 get(const int64_t index) const final
782  {
783  const PointIndices indices = lookup_point_indices(offsets_, index);
784  const Spline &spline = *splines_[indices.spline_index];
785  if (spline.type() == CURVE_TYPE_BEZIER) {
786  const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(spline);
787  return is_right_ ? bezier_spline.handle_positions_right()[indices.point_index] :
788  bezier_spline.handle_positions_left()[indices.point_index];
789  }
790  return float3(0);
791  }
792 
793  void set(const int64_t index, float3 value) final
794  {
795  const PointIndices indices = lookup_point_indices(offsets_, index);
796  Spline &spline = *splines_[indices.spline_index];
797  if (spline.type() == CURVE_TYPE_BEZIER) {
798  BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
799  if (is_right_) {
800  bezier_spline.handle_positions_right()[indices.point_index] = value;
801  }
802  else {
803  bezier_spline.handle_positions_left()[indices.point_index] = value;
804  }
805  bezier_spline.mark_cache_invalid();
806  }
807  }
808 
810  {
811  for (const int spline_index : splines_.index_range()) {
812  Spline &spline = *splines_[spline_index];
813  if (spline.type() == CURVE_TYPE_BEZIER) {
814  const int offset = offsets_[spline_index];
815 
816  BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
817  if (is_right_) {
818  for (const int i : IndexRange(bezier_spline.size())) {
819  bezier_spline.handle_positions_right()[i] = src[offset + i];
820  }
821  }
822  else {
823  for (const int i : IndexRange(bezier_spline.size())) {
824  bezier_spline.handle_positions_left()[i] = src[offset + i];
825  }
826  }
827  bezier_spline.mark_cache_invalid();
828  }
829  }
830  }
831 
832  void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
833  {
834  Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
835  point_attribute_materialize(spans.as_span(), offsets_, mask, r_span);
836  }
837 
839  {
840  Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
841  point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span);
842  }
843 
851  {
852  Array<Span<float3>> spans(splines.size());
853  for (const int i : spans.index_range()) {
854  if (splines[i]->type() == CURVE_TYPE_BEZIER) {
855  BezierSpline &bezier_spline = static_cast<BezierSpline &>(*splines[i]);
856  spans[i] = is_right ? bezier_spline.handle_positions_right() :
857  bezier_spline.handle_positions_left();
858  }
859  else {
860  spans[i] = {};
861  }
862  }
863  return spans;
864  }
865 };
866 
871 template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttributeProvider {
872  protected:
873  using GetSpan = Span<T> (*)(const Spline &spline);
874  using GetMutableSpan = MutableSpan<T> (*)(Spline &spline);
875  using UpdateOnWrite = void (*)(Spline &spline);
880 
881  public:
882  BuiltinPointAttributeProvider(std::string attribute_name,
883  const CreatableEnum creatable,
884  const DeletableEnum deletable,
885  const GetSpan get_span,
886  const GetMutableSpan get_mutable_span,
887  const UpdateOnWrite update_on_write,
888  const bool stored_in_custom_data)
889  : BuiltinAttributeProvider(std::move(attribute_name),
891  bke::cpp_type_to_custom_data_type(CPPType::get<T>()),
892  creatable,
894  deletable),
895  get_span_(get_span),
896  get_mutable_span_(get_mutable_span),
897  update_on_write_(update_on_write),
898  stored_in_custom_data_(stored_in_custom_data)
899  {
900  }
901 
902  GVArray try_get_for_read(const void *owner) const override
903  {
904  const CurveEval *curve = static_cast<const CurveEval *>(owner);
905  if (curve == nullptr) {
906  return {};
907  }
908 
909  if (!this->exists(owner)) {
910  return {};
911  }
912 
913  Span<SplinePtr> splines = curve->splines();
914  if (splines.size() == 1) {
916  }
917 
918  Array<int> offsets = curve->control_point_offsets();
919  Array<MutableSpan<T>> spans(splines.size());
920  for (const int i : splines.index_range()) {
921  Span<T> span = get_span_(*splines[i]);
922  /* Use const-cast because the underlying virtual array implementation is shared between const
923  * and non const data. */
924  spans[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
925  }
926 
927  return point_data_varray(spans, offsets);
928  }
929 
930  GAttributeWriter try_get_for_write(void *owner) const override
931  {
932  CurveEval *curve = static_cast<CurveEval *>(owner);
933  if (curve == nullptr) {
934  return {};
935  }
936 
937  if (!this->exists(owner)) {
938  return {};
939  }
940 
941  std::function<void()> tag_modified_fn;
942  if (update_on_write_ != nullptr) {
943  tag_modified_fn = [curve, update = update_on_write_]() {
944  for (SplinePtr &spline : curve->splines()) {
945  update(*spline);
946  }
947  };
948  }
949 
950  MutableSpan<SplinePtr> splines = curve->splines();
951  if (splines.size() == 1) {
953  domain_,
954  std::move(tag_modified_fn)};
955  }
956 
957  Array<int> offsets = curve->control_point_offsets();
958  Array<MutableSpan<T>> spans(splines.size());
959  for (const int i : splines.index_range()) {
960  spans[i] = get_mutable_span_(*splines[i]);
961  }
962 
963  return {point_data_varray_mutable(spans, offsets), domain_, tag_modified_fn};
964  }
965 
966  bool try_delete(void *owner) const final
967  {
968  if (deletable_ == DeletableEnum::NonDeletable) {
969  return false;
970  }
971  CurveEval *curve = static_cast<CurveEval *>(owner);
973  }
974 
975  bool try_create(void *owner, const AttributeInit &initializer) const final
976  {
977  if (createable_ == CreatableEnum::NonCreatable) {
978  return false;
979  }
980  CurveEval *curve = static_cast<CurveEval *>(owner);
981  return create_point_attribute(curve, name_, initializer, CD_PROP_INT32);
982  }
983 
984  bool exists(const void *owner) const final
985  {
986  const CurveEval *curve = static_cast<const CurveEval *>(owner);
987  if (curve == nullptr) {
988  return false;
989  }
990 
991  Span<SplinePtr> splines = curve->splines();
992  if (splines.size() == 0) {
993  return false;
994  }
995 
997  if (!curve->splines().first()->attributes.get_for_read(name_)) {
998  return false;
999  }
1000  }
1001 
1002  bool has_point = false;
1003  for (const SplinePtr &spline : curve->splines()) {
1004  if (spline->size() != 0) {
1005  has_point = true;
1006  break;
1007  }
1008  }
1009 
1010  if (!has_point) {
1011  return false;
1012  }
1013 
1014  return true;
1015  }
1016 };
1017 
1024  public:
1027  "position",
1030  [](const Spline &spline) { return spline.positions(); },
1031  [](Spline &spline) { return spline.positions(); },
1032  [](Spline &spline) { spline.mark_cache_invalid(); },
1033  false)
1034  {
1035  }
1036 
1037  GAttributeWriter try_get_for_write(void *owner) const final
1038  {
1039  CurveEval *curve = static_cast<CurveEval *>(owner);
1040  if (curve == nullptr) {
1041  return {};
1042  }
1043 
1044  /* Use the regular position virtual array when there aren't any Bezier splines
1045  * to avoid the overhead of checking the spline type for every point. */
1046  if (!curve->has_spline_with_type(CURVE_TYPE_BEZIER)) {
1048  }
1049 
1050  auto tag_modified_fn = [curve]() {
1051  /* Changing the positions requires recalculation of cached evaluated data in many cases.
1052  * This could set more specific flags in the future to avoid unnecessary recomputation. */
1053  curve->mark_cache_invalid();
1054  };
1055 
1056  Array<int> offsets = curve->control_point_offsets();
1058  std::move(offsets)),
1059  domain_,
1060  tag_modified_fn};
1061  }
1062 };
1063 
1065  private:
1066  bool is_right_;
1067 
1068  public:
1069  BezierHandleAttributeProvider(const bool is_right)
1070  : BuiltinAttributeProvider(is_right ? "handle_right" : "handle_left",
1076  is_right_(is_right)
1077  {
1078  }
1079 
1080  GVArray try_get_for_read(const void *owner) const override
1081  {
1082  const CurveEval *curve = static_cast<const CurveEval *>(owner);
1083  if (curve == nullptr) {
1084  return {};
1085  }
1086 
1087  if (!curve->has_spline_with_type(CURVE_TYPE_BEZIER)) {
1088  return {};
1089  }
1090 
1091  Array<int> offsets = curve->control_point_offsets();
1092  /* Use const-cast because the underlying virtual array implementation is shared between const
1093  * and non const data. */
1095  const_cast<CurveEval *>(curve)->splines(), std::move(offsets), is_right_);
1096  }
1097 
1098  GAttributeWriter try_get_for_write(void *owner) const override
1099  {
1100  CurveEval *curve = static_cast<CurveEval *>(owner);
1101  if (curve == nullptr) {
1102  return {};
1103  }
1104 
1105  if (!curve->has_spline_with_type(CURVE_TYPE_BEZIER)) {
1106  return {};
1107  }
1108 
1109  auto tag_modified_fn = [curve]() { curve->mark_cache_invalid(); };
1110 
1111  Array<int> offsets = curve->control_point_offsets();
1113  curve->splines(), std::move(offsets), is_right_),
1114  domain_,
1115  tag_modified_fn};
1116  }
1117 
1118  bool try_delete(void *UNUSED(owner)) const final
1119  {
1120  return false;
1121  }
1122 
1123  bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
1124  {
1125  return false;
1126  }
1127 
1128  bool exists(const void *owner) const final
1129  {
1130  const CurveEval *curve = static_cast<const CurveEval *>(owner);
1131  if (curve == nullptr) {
1132  return false;
1133  }
1134 
1136  component.replace(const_cast<CurveEval *>(curve), GeometryOwnershipType::ReadOnly);
1137 
1138  return curve->has_spline_with_type(CURVE_TYPE_BEZIER) && !curve->splines().is_empty();
1139  }
1140 };
1141 
1144 /* -------------------------------------------------------------------- */
1154  private:
1155  static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 |
1159 
1160  public:
1162  const AttributeIDRef &attribute_id) const final
1163  {
1164  const CurveEval *curve = static_cast<const CurveEval *>(owner);
1165  if (curve == nullptr || curve->splines().size() == 0) {
1166  return {};
1167  }
1168 
1169  Span<SplinePtr> splines = curve->splines();
1170  Vector<GSpan> spans; /* GSpan has no default constructor. */
1171  spans.reserve(splines.size());
1172  std::optional<GSpan> first_span = splines[0]->attributes.get_for_read(attribute_id);
1173  if (!first_span) {
1174  return {};
1175  }
1176  spans.append(*first_span);
1177  for (const int i : IndexRange(1, splines.size() - 1)) {
1178  std::optional<GSpan> span = splines[i]->attributes.get_for_read(attribute_id);
1179  if (!span) {
1180  /* All splines should have the same set of data layers. It would be possible to recover
1181  * here and return partial data instead, but that would add a lot of complexity for a
1182  * situation we don't even expect to encounter. */
1184  return {};
1185  }
1186  if (span->type() != spans.last().type()) {
1187  /* Data layer types on separate splines do not match. */
1189  return {};
1190  }
1191  spans.append(*span);
1192  }
1193 
1194  /* First check for the simpler situation when we can return a simpler span virtual array. */
1195  if (spans.size() == 1) {
1196  return {GVArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
1197  }
1198 
1200  Array<int> offsets = curve->control_point_offsets();
1201  attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
1202  using T = decltype(dummy);
1204  for (const int i : splines.index_range()) {
1205  Span<T> span = spans[i].typed<T>();
1206  /* Use const-cast because the underlying virtual array implementation is shared between
1207  * const and non const data. */
1208  data[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
1209  BLI_assert(data[i].data() != nullptr);
1210  }
1212  });
1213  return attribute;
1214  }
1215 
1216  /* This function is almost the same as #try_get_for_read, but without const. */
1217  GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
1218  {
1219  CurveEval *curve = static_cast<CurveEval *>(owner);
1220  if (curve == nullptr || curve->splines().size() == 0) {
1221  return {};
1222  }
1223 
1224  MutableSpan<SplinePtr> splines = curve->splines();
1225  Vector<GMutableSpan> spans; /* GMutableSpan has no default constructor. */
1226  spans.reserve(splines.size());
1227  std::optional<GMutableSpan> first_span = splines[0]->attributes.get_for_write(attribute_id);
1228  if (!first_span) {
1229  return {};
1230  }
1231  spans.append(*first_span);
1232  for (const int i : IndexRange(1, splines.size() - 1)) {
1233  std::optional<GMutableSpan> span = splines[i]->attributes.get_for_write(attribute_id);
1234  if (!span) {
1235  /* All splines should have the same set of data layers. It would be possible to recover
1236  * here and return partial data instead, but that would add a lot of complexity for a
1237  * situation we don't even expect to encounter. */
1239  return {};
1240  }
1241  if (span->type() != spans.last().type()) {
1242  /* Data layer types on separate splines do not match. */
1244  return {};
1245  }
1246  spans.append(*span);
1247  }
1248 
1249  /* First check for the simpler situation when we can return a simpler span virtual array. */
1250  if (spans.size() == 1) {
1251  return {GVMutableArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
1252  }
1253 
1255  Array<int> offsets = curve->control_point_offsets();
1256  attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
1257  using T = decltype(dummy);
1259  for (const int i : splines.index_range()) {
1260  data[i] = spans[i].typed<T>();
1261  BLI_assert(data[i].data() != nullptr);
1262  }
1264  });
1265  return attribute;
1266  }
1267 
1268  bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
1269  {
1270  CurveEval *curve = static_cast<CurveEval *>(owner);
1271  return remove_point_attribute(curve, attribute_id);
1272  }
1273 
1274  bool try_create(void *owner,
1275  const AttributeIDRef &attribute_id,
1276  const eAttrDomain domain,
1277  const eCustomDataType data_type,
1278  const AttributeInit &initializer) const final
1279  {
1280  BLI_assert(this->type_is_supported(data_type));
1281  if (domain != ATTR_DOMAIN_POINT) {
1282  return false;
1283  }
1284  CurveEval *curve = static_cast<CurveEval *>(owner);
1285  return create_point_attribute(curve, attribute_id, initializer, data_type);
1286  }
1287 
1288  bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
1289  {
1290  const CurveEval *curve = static_cast<const CurveEval *>(owner);
1291  if (curve == nullptr || curve->splines().size() == 0) {
1292  return false;
1293  }
1294 
1295  Span<SplinePtr> splines = curve->splines();
1296 
1297  /* In a debug build, check that all corresponding custom data layers have the same type. */
1298  curve->assert_valid_point_attributes();
1299 
1300  /* Use the first spline as a representative for all the others. */
1301  splines.first()->attributes.foreach_attribute(callback, ATTR_DOMAIN_POINT);
1302 
1303  return true;
1304  }
1305 
1306  void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
1307  {
1309  }
1310 
1311  bool type_is_supported(eCustomDataType data_type) const
1312  {
1313  return ((1ULL << data_type) & supported_types_mask) != 0;
1314  }
1315 };
1316 
1319 /* -------------------------------------------------------------------- */
1328 {
1329  static BuiltinSplineAttributeProvider resolution("resolution",
1330  CD_PROP_INT32,
1334 
1335  static BuiltinSplineAttributeProvider cyclic("cyclic",
1336  CD_PROP_BOOL,
1340 
1341  static CustomDataAccessInfo spline_custom_data_access = {
1342  [](void *owner) -> CustomData * {
1343  CurveEval *curve = static_cast<CurveEval *>(owner);
1344  return curve ? &curve->attributes.data : nullptr;
1345  },
1346  [](const void *owner) -> const CustomData * {
1347  const CurveEval *curve = static_cast<const CurveEval *>(owner);
1348  return curve ? &curve->attributes.data : nullptr;
1349  },
1350  [](const void *owner) -> int {
1351  const CurveEval *curve = static_cast<const CurveEval *>(owner);
1352  return curve->splines().size();
1353  },
1354  nullptr};
1355 
1356  static CustomDataAttributeProvider spline_custom_data(ATTR_DOMAIN_CURVE,
1357  spline_custom_data_access);
1358 
1359  static PositionAttributeProvider position;
1360  static BezierHandleAttributeProvider handles_start(false);
1361  static BezierHandleAttributeProvider handles_end(true);
1362 
1364  "id",
1367  [](const Spline &spline) {
1368  std::optional<GSpan> span = spline.attributes.get_for_read("id");
1369  return span ? span->typed<int>() : Span<int>();
1370  },
1371  [](Spline &spline) {
1372  std::optional<GMutableSpan> span = spline.attributes.get_for_write("id");
1373  return span ? span->typed<int>() : MutableSpan<int>();
1374  },
1375  {},
1376  true);
1377 
1379  "radius",
1382  [](const Spline &spline) { return spline.radii(); },
1383  [](Spline &spline) { return spline.radii(); },
1384  nullptr,
1385  false);
1386 
1388  "tilt",
1391  [](const Spline &spline) { return spline.tilts(); },
1392  [](Spline &spline) { return spline.tilts(); },
1393  [](Spline &spline) { spline.mark_cache_invalid(); },
1394  false);
1395 
1396  static DynamicPointAttributeProvider point_custom_data;
1397 
1399  {&position, &id, &radius, &tilt, &handles_start, &handles_end, &resolution, &cyclic},
1400  {&spline_custom_data, &point_custom_data});
1401 }
1402 
1406 {
1409  attribute_accessor_functions::accessor_functions_for_providers<providers>();
1410  fn.domain_size = [](const void *owner, const eAttrDomain domain) -> int {
1411  if (owner == nullptr) {
1412  return 0;
1413  }
1414  const CurveEval &curve_eval = *static_cast<const CurveEval *>(owner);
1415  switch (domain) {
1416  case ATTR_DOMAIN_POINT:
1417  return curve_eval.total_control_point_num();
1418  case ATTR_DOMAIN_CURVE:
1419  return curve_eval.splines().size();
1420  default:
1421  return 0;
1422  }
1423  };
1424  fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
1425  return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
1426  };
1427  fn.adapt_domain = [](const void *owner,
1428  const blender::GVArray &varray,
1429  const eAttrDomain from_domain,
1430  const eAttrDomain to_domain) -> GVArray {
1431  if (owner == nullptr) {
1432  return {};
1433  }
1434  const CurveEval &curve_eval = *static_cast<const CurveEval *>(owner);
1435  return adapt_curve_attribute_domain(curve_eval, varray, from_domain, to_domain);
1436  };
1437  return fn;
1438 }
1439 
1441 {
1443  return fn;
1444 }
1445 
1446 } // namespace blender::bke
1447 
1448 std::optional<blender::bke::AttributeAccessor> CurveComponentLegacy::attributes() const
1449 {
1451 }
1452 
1453 std::optional<blender::bke::MutableAttributeAccessor> CurveComponentLegacy::attributes_for_write()
1454 {
1455  CurveEval *curve = this->get_for_write();
1458 }
1459 
1461 {
1464 }
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_CURVE
Definition: BKE_attribute.h:31
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
@ GEO_COMPONENT_TYPE_CURVE
GeometryOwnershipType
std::unique_ptr< Spline > SplinePtr
Definition: BKE_spline.hh:26
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define final(a, b, c)
Definition: BLI_hash.h:21
#define UNUSED(x)
#define ELEM(...)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
Enumerations for DNA_ID.h.
@ CURVE_TYPE_BEZIER
#define CD_MASK_PROP_COLOR
#define CD_MASK_PROP_FLOAT3
#define CD_MASK_PROP_FLOAT2
eCustomDataType
@ CD_PROP_FLOAT3
@ CD_PROP_INT32
@ CD_PROP_BOOL
#define CD_MASK_PROP_BOOL
#define CD_MASK_PROP_INT32
#define CD_MASK_PROP_FLOAT
#define CD_MASK_PROP_INT8
_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
int size() const final
blender::Span< blender::float3 > handle_positions_right() const
blender::Span< blender::float3 > handle_positions_left() const
void mark_cache_invalid() final
GeometryComponent * copy() const override
void ensure_owns_direct_data() override
void replace(CurveEval *curve, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const CurveEval * get_for_read() const
std::optional< blender::bke::AttributeAccessor > attributes() const final
bool owns_direct_data() const override
std::optional< blender::bke::MutableAttributeAccessor > attributes_for_write() final
bool is_mutable() const
Definition: geometry_set.cc:97
virtual blender::MutableSpan< blender::float3 > positions()=0
CurveType type() const
Definition: spline_base.cc:25
virtual blender::MutableSpan< float > tilts()=0
blender::bke::CustomDataAttributes attributes
Definition: BKE_spline.hh:56
virtual blender::MutableSpan< float > radii()=0
virtual void mark_cache_invalid()=0
const T & last(const int64_t n=0) const
Definition: BLI_array.hh:284
IndexRange index_range() const
Definition: BLI_array.hh:348
Span< T > as_span() const
Definition: BLI_array.hh:231
void fill(const T &value) const
Definition: BLI_array.hh:260
const CPPType & type() const
static GVArray ForSpan(GSpan span)
void set_all(const void *src)
static GVMutableArray ForSpan(GMutableSpan span)
constexpr int64_t size() const
Definition: BLI_span.hh:511
constexpr void fill(const T &value)
Definition: BLI_span.hh:527
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition: BLI_span.hh:581
constexpr void copy_from(Span< T > values)
Definition: BLI_span.hh:707
constexpr IndexRange index_range() const
Definition: BLI_span.hh:661
constexpr T * data() const
Definition: BLI_span.hh:548
constexpr const T * data() const
Definition: BLI_span.hh:203
constexpr const T & last(const int64_t n=0) const
Definition: BLI_span.hh:313
constexpr int64_t size() const
Definition: BLI_span.hh:240
constexpr IndexRange index_range() const
Definition: BLI_span.hh:401
constexpr const T * end() const
Definition: BLI_span.hh:212
constexpr const T * begin() const
Definition: BLI_span.hh:208
int64_t size() const
Definition: BLI_vector.hh:694
void append(const T &value)
Definition: BLI_vector.hh:433
const T & last(const int64_t n=0) const
Definition: BLI_vector.hh:663
const T & first() const
Definition: BLI_vector.hh:680
void reserve(const int64_t min_capacity)
Definition: BLI_vector.hh:340
GVArray try_get_for_read(const void *owner) const override
bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
GAttributeWriter try_get_for_write(void *owner) const override
bool try_delete(void *UNUSED(owner)) const final
GAttributeWriter try_get_for_write(void *owner) const override
BuiltinPointAttributeProvider(std::string attribute_name, const CreatableEnum creatable, const DeletableEnum deletable, const GetSpan get_span, const GetMutableSpan get_mutable_span, const UpdateOnWrite update_on_write, const bool stored_in_custom_data)
bool try_create(void *owner, const AttributeInit &initializer) const final
GVArray try_get_for_read(const void *owner) const override
GAttributeWriter try_get_for_write(void *owner) const final
BuiltinSplineAttributeProvider(std::string attribute_name, const eCustomDataType attribute_type, const WritableEnum writable, const AsReadAttribute as_read_attribute, const AsWriteAttribute as_write_attribute)
GVArray try_get_for_read(const void *owner) const final
bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
bool try_delete(void *UNUSED(owner)) const final
std::optional< blender::GSpan > get_for_read(const AttributeIDRef &attribute_id) const
std::optional< blender::GMutableSpan > get_for_write(const AttributeIDRef &attribute_id)
GAttributeReader try_get_for_read(const void *owner, const AttributeIDRef &attribute_id) const final
bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
void foreach_domain(const FunctionRef< void(eAttrDomain)> callback) const final
bool type_is_supported(eCustomDataType data_type) const
GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
bool try_create(void *owner, const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer) const final
GAttributeWriter try_get_for_write(void *owner) const final
void materialize(const IndexMask mask, MutableSpan< float3 > r_span) const final
void set(const int64_t index, float3 value) final
static Array< Span< float3 > > get_handle_spans(Span< SplinePtr > splines, const bool is_right)
void materialize_to_uninitialized(const IndexMask mask, MutableSpan< float3 > r_span) const final
float3 get(const int64_t index) const final
VArrayImpl_For_BezierHandles(MutableSpan< SplinePtr > splines, Array< int > offsets, const bool is_right)
void materialize_to_uninitialized(const IndexMask mask, MutableSpan< T > r_span) const final
void materialize(const IndexMask mask, MutableSpan< T > r_span) const final
VArrayImpl_For_SplinePoints(Array< MutableSpan< T >> data, Array< int > offsets)
void set(const int64_t index, T value) final
void set(const int64_t index, float3 value) final
float3 get(const int64_t index) const final
void materialize(const IndexMask mask, MutableSpan< float3 > r_span) const final
void materialize_to_uninitialized(const IndexMask mask, MutableSpan< float3 > r_span) const final
VArrayImpl_For_SplinePosition(MutableSpan< SplinePtr > splines, Array< int > offsets)
void materialize(const IndexMask mask, MutableSpan< T > r_span) const final
VArray_For_SplineToPoint(GVArray original_varray, Array< int > offsets)
T get(const int64_t index) const final
void materialize_to_uninitialized(const IndexMask mask, MutableSpan< T > r_span) const final
Curve curve
DEGForeachIDComponentCallback callback
SyclQueue void void * src
SyclQueue void void size_t num_bytes void
T * data_
Definition: eval_output.h:163
static GVArray adapt_curve_attribute_domain(const CurveEval &curve, const GVArray &varray, const eAttrDomain from_domain, const eAttrDomain to_domain)
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ccl_gpu_kernel_postfix int ccl_global int * indices
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
ListBase splines
Definition: mask.c:265
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
#define T
typename DefaultMixerStruct< T >::type DefaultMixer
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
const blender::CPPType * custom_data_type_to_cpp_type(const eCustomDataType type)
Definition: customdata.cc:5312
static int get_spline_resolution(const SplinePtr &spline)
static bool get_cyclic_value(const SplinePtr &spline)
static bool remove_point_attribute(CurveEval *curve, const AttributeIDRef &attribute_id)
static bool create_point_attribute(CurveEval *curve, const AttributeIDRef &attribute_id, const AttributeInit &initializer, const eCustomDataType data_type)
static GVMutableArray make_cyclic_write_attribute(CurveEval &curve)
static void point_attribute_materialize(Span< Span< T >> data, Span< int > offsets, const IndexMask mask, MutableSpan< T > r_span)
static void set_spline_resolution(SplinePtr &spline, const int resolution)
static void adapt_curve_domain_point_to_spline_impl(const CurveEval &curve, const VArray< T > &old_values, MutableSpan< T > r_values)
VArray< T > point_data_varray(Array< MutableSpan< T >> spans, Array< int > offsets)
static void set_cyclic_value(SplinePtr &spline, const bool value)
static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArray varray)
static ComponentAttributeProviders create_attribute_providers_for_curve()
VMutableArray< T > point_data_varray_mutable(Array< MutableSpan< T >> spans, Array< int > offsets)
static GVArray make_resolution_read_attribute(const CurveEval &curve)
static GVArray make_cyclic_read_attribute(const CurveEval &curve)
static GVMutableArray make_resolution_write_attribute(CurveEval &curve)
static AttributeAccessorFunctions get_curve_accessor_functions()
static PointIndices lookup_point_indices(Span< int > offsets, const int index)
static void point_attribute_materialize_to_uninitialized(Span< Span< T >> data, Span< int > offsets, const IndexMask mask, MutableSpan< T > r_span)
static const AttributeAccessorFunctions & get_curve_accessor_functions_ref()
static GVArray varray_from_initializer(const AttributeInit &initializer, const eCustomDataType data_type, const Span< SplinePtr > splines)
eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
Definition: customdata.cc:5337
static GVArray adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArray varray)
vec_base< float, 3 > float3
void uninitialized_fill_n(T *dst, int64_t n, const T &value)
void uninitialized_copy_n(const T *src, int64_t n, T *dst)
static void update(bNodeTree *ntree)
__int64 int64_t
Definition: stdint.h:89
unsigned __int64 uint64_t
Definition: stdint.h:90
blender::Span< SplinePtr > splines() const
Definition: curve_eval.cc:36
blender::bke::MutableAttributeAccessor attributes_for_write()
int total_control_point_num() const
Definition: curve_eval.cc:118
float size[3]
void * first
Definition: DNA_listBase.h:31
bool(* domain_supported)(const void *owner, eAttrDomain domain)
GVArray(* adapt_domain)(const void *owner, const GVArray &varray, eAttrDomain from_domain, eAttrDomain to_domain)
int(* domain_size)(const void *owner, eAttrDomain domain)
float max