Blender  V3.3
geometry_component_mesh.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_listbase.h"
4 #include "BLI_task.hh"
5 
6 #include "DNA_mesh_types.h"
7 #include "DNA_meshdata_types.h"
8 #include "DNA_object_types.h"
9 
10 #include "BKE_attribute_math.hh"
11 #include "BKE_deform.h"
12 #include "BKE_geometry_fields.hh"
13 #include "BKE_geometry_set.hh"
14 #include "BKE_lib_id.h"
15 #include "BKE_mesh.h"
16 
18 
20 
21 /* -------------------------------------------------------------------- */
26 {
27 }
28 
30 {
31  this->clear();
32 }
33 
35 {
36  MeshComponent *new_component = new MeshComponent();
37  if (mesh_ != nullptr) {
38  new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
39  new_component->ownership_ = GeometryOwnershipType::Owned;
40  }
41  return new_component;
42 }
43 
45 {
46  BLI_assert(this->is_mutable());
47  if (mesh_ != nullptr) {
48  if (ownership_ == GeometryOwnershipType::Owned) {
49  BKE_id_free(nullptr, mesh_);
50  }
51  mesh_ = nullptr;
52  }
53 }
54 
56 {
57  return mesh_ != nullptr;
58 }
59 
61 {
62  BLI_assert(this->is_mutable());
63  this->clear();
64  mesh_ = mesh;
65  ownership_ = ownership;
66 }
67 
69 {
70  BLI_assert(this->is_mutable());
71  Mesh *mesh = mesh_;
72  mesh_ = nullptr;
73  return mesh;
74 }
75 
77 {
78  return mesh_;
79 }
80 
82 {
83  BLI_assert(this->is_mutable());
84  if (ownership_ == GeometryOwnershipType::ReadOnly) {
85  mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
86  ownership_ = GeometryOwnershipType::Owned;
87  }
88  return mesh_;
89 }
90 
92 {
93  return mesh_ == nullptr;
94 }
95 
97 {
98  return ownership_ == GeometryOwnershipType::Owned;
99 }
100 
102 {
103  BLI_assert(this->is_mutable());
104  if (ownership_ != GeometryOwnershipType::Owned) {
105  mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
106  ownership_ = GeometryOwnershipType::Owned;
107  }
108 }
109 
112 /* -------------------------------------------------------------------- */
116 namespace blender::bke {
117 
119  const Mesh &mesh,
120  const IndexMask mask,
121  const eAttrDomain domain)
122 {
123  switch (domain) {
124  case ATTR_DOMAIN_FACE: {
127  }
128  case ATTR_DOMAIN_POINT: {
131  }
132  case ATTR_DOMAIN_EDGE: {
133  /* In this case, start with vertex normals and convert to the edge domain, since the
134  * conversion from edges to vertices is very simple. Use "manual" domain interpolation
135  * instead of the GeometryComponent API to avoid calculating unnecessary values and to
136  * allow normalizing the result more simply. */
138  Array<float3> edge_normals(mask.min_array_size());
140  for (const int i : mask) {
141  const MEdge &edge = edges[i];
142  edge_normals[i] = math::normalize(
143  math::interpolate(vert_normals[edge.v1], vert_normals[edge.v2], 0.5f));
144  }
145 
146  return VArray<float3>::ForContainer(std::move(edge_normals));
147  }
148  case ATTR_DOMAIN_CORNER: {
149  /* The normals on corners are just the mesh's face normals, so start with the face normal
150  * array and copy the face normal for each of its corners. In this case using the mesh
151  * component's generic domain interpolation is fine, the data will still be normalized,
152  * since the face normal is just copied to every corner. */
153  return mesh_component.attributes()->adapt_domain(
157  }
158  default:
159  return {};
160  }
161 }
162 
163 } // namespace blender::bke
164 
167 /* -------------------------------------------------------------------- */
171 namespace blender::bke {
172 
173 template<typename T>
175  const VArray<T> &old_values,
176  MutableSpan<T> r_values)
177 {
178  BLI_assert(r_values.size() == mesh.totvert);
179  attribute_math::DefaultMixer<T> mixer(r_values);
180 
181  for (const int loop_index : IndexRange(mesh.totloop)) {
182  const T value = old_values[loop_index];
183  const MLoop &loop = mesh.mloop[loop_index];
184  const int point_index = loop.v;
185  mixer.mix_in(point_index, value);
186  }
187  mixer.finalize();
188 }
189 
190 /* A vertex is selected if all connected face corners were selected and it is not loose. */
191 template<>
193  const VArray<bool> &old_values,
194  MutableSpan<bool> r_values)
195 {
196  BLI_assert(r_values.size() == mesh.totvert);
197  Array<bool> loose_verts(mesh.totvert, true);
198 
199  r_values.fill(true);
200  for (const int loop_index : IndexRange(mesh.totloop)) {
201  const MLoop &loop = mesh.mloop[loop_index];
202  const int point_index = loop.v;
203 
204  loose_verts[point_index] = false;
205  if (!old_values[loop_index]) {
206  r_values[point_index] = false;
207  }
208  }
209 
210  /* Deselect loose vertices without corners that are still selected from the 'true' default. */
211  for (const int vert_index : IndexRange(mesh.totvert)) {
212  if (loose_verts[vert_index]) {
213  r_values[vert_index] = false;
214  }
215  }
216 }
217 
219 {
220  GVArray new_varray;
221  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
222  using T = decltype(dummy);
223  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
224  /* We compute all interpolated values at once, because for this interpolation, one has to
225  * iterate over all loops anyway. */
226  Array<T> values(mesh.totvert);
227  adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray.typed<T>(), values);
228  new_varray = VArray<T>::ForContainer(std::move(values));
229  }
230  });
231  return new_varray;
232 }
233 
238 {
239  GVArray new_varray;
240  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
241  using T = decltype(dummy);
242  new_varray = VArray<T>::ForFunc(mesh.totloop,
243  [&mesh, varray = varray.typed<T>()](const int64_t loop_index) {
244  const int vertex_index = mesh.mloop[loop_index].v;
245  return varray[vertex_index];
246  });
247  });
248  return new_varray;
249 }
250 
252 {
253  GVArray new_varray;
254  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
255  using T = decltype(dummy);
256  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
257  if constexpr (std::is_same_v<T, bool>) {
258  new_varray = VArray<T>::ForFunc(
259  mesh.totpoly, [&mesh, varray = varray.typed<bool>()](const int face_index) {
260  /* A face is selected if all of its corners were selected. */
261  const MPoly &poly = mesh.mpoly[face_index];
262  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
263  if (!varray[loop_index]) {
264  return false;
265  }
266  }
267  return true;
268  });
269  }
270  else {
271  new_varray = VArray<T>::ForFunc(
272  mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) {
273  T return_value;
274  attribute_math::DefaultMixer<T> mixer({&return_value, 1});
275  const MPoly &poly = mesh.mpoly[face_index];
276  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
277  const T value = varray[loop_index];
278  mixer.mix_in(0, value);
279  }
280  mixer.finalize();
281  return return_value;
282  });
283  }
284  }
285  });
286  return new_varray;
287 }
288 
289 template<typename T>
291  const VArray<T> &old_values,
292  MutableSpan<T> r_values)
293 {
294  BLI_assert(r_values.size() == mesh.totedge);
295  attribute_math::DefaultMixer<T> mixer(r_values);
296 
297  for (const int poly_index : IndexRange(mesh.totpoly)) {
298  const MPoly &poly = mesh.mpoly[poly_index];
299 
300  /* For every edge, mix values from the two adjacent corners (the current and next corner). */
301  for (const int i : IndexRange(poly.totloop)) {
302  const int next_i = (i + 1) % poly.totloop;
303  const int loop_i = poly.loopstart + i;
304  const int next_loop_i = poly.loopstart + next_i;
305  const MLoop &loop = mesh.mloop[loop_i];
306  const int edge_index = loop.e;
307  mixer.mix_in(edge_index, old_values[loop_i]);
308  mixer.mix_in(edge_index, old_values[next_loop_i]);
309  }
310  }
311 
312  mixer.finalize();
313 }
314 
315 /* An edge is selected if all corners on adjacent faces were selected. */
316 template<>
318  const VArray<bool> &old_values,
319  MutableSpan<bool> r_values)
320 {
321  BLI_assert(r_values.size() == mesh.totedge);
322 
323  /* It may be possible to rely on the #ME_LOOSEEDGE flag, but that seems error-prone. */
324  Array<bool> loose_edges(mesh.totedge, true);
325 
326  r_values.fill(true);
327  for (const int poly_index : IndexRange(mesh.totpoly)) {
328  const MPoly &poly = mesh.mpoly[poly_index];
329 
330  for (const int i : IndexRange(poly.totloop)) {
331  const int next_i = (i + 1) % poly.totloop;
332  const int loop_i = poly.loopstart + i;
333  const int next_loop_i = poly.loopstart + next_i;
334  const MLoop &loop = mesh.mloop[loop_i];
335  const int edge_index = loop.e;
336 
337  loose_edges[edge_index] = false;
338 
339  if (!old_values[loop_i] || !old_values[next_loop_i]) {
340  r_values[edge_index] = false;
341  }
342  }
343  }
344 
345  /* Deselect loose edges without corners that are still selected from the 'true' default. */
346  threading::parallel_for(IndexRange(mesh.totedge), 2048, [&](const IndexRange range) {
347  for (const int edge_index : range) {
348  if (loose_edges[edge_index]) {
349  r_values[edge_index] = false;
350  }
351  }
352  });
353 }
354 
356 {
357  GVArray new_varray;
358  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
359  using T = decltype(dummy);
360  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
361  Array<T> values(mesh.totedge);
362  adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray.typed<T>(), values);
363  new_varray = VArray<T>::ForContainer(std::move(values));
364  }
365  });
366  return new_varray;
367 }
368 
369 template<typename T>
371  const VArray<T> &old_values,
372  MutableSpan<T> r_values)
373 {
374  BLI_assert(r_values.size() == mesh.totvert);
375  attribute_math::DefaultMixer<T> mixer(r_values);
376 
377  for (const int poly_index : IndexRange(mesh.totpoly)) {
378  const MPoly &poly = mesh.mpoly[poly_index];
379  const T value = old_values[poly_index];
380  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
381  const MLoop &loop = mesh.mloop[loop_index];
382  const int point_index = loop.v;
383  mixer.mix_in(point_index, value);
384  }
385  }
386 
387  mixer.finalize();
388 }
389 
390 /* A vertex is selected if any of the connected faces were selected. */
391 template<>
393  const VArray<bool> &old_values,
394  MutableSpan<bool> r_values)
395 {
396  BLI_assert(r_values.size() == mesh.totvert);
397 
398  r_values.fill(false);
399  for (const int poly_index : IndexRange(mesh.totpoly)) {
400  const MPoly &poly = mesh.mpoly[poly_index];
401  if (old_values[poly_index]) {
402  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
403  const MLoop &loop = mesh.mloop[loop_index];
404  const int vert_index = loop.v;
405  r_values[vert_index] = true;
406  }
407  }
408  }
409 }
410 
412 {
413  GVArray new_varray;
414  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
415  using T = decltype(dummy);
416  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
417  Array<T> values(mesh.totvert);
418  adapt_mesh_domain_face_to_point_impl<T>(mesh, varray.typed<T>(), values);
419  new_varray = VArray<T>::ForContainer(std::move(values));
420  }
421  });
422  return new_varray;
423 }
424 
425 /* Each corner's value is simply a copy of the value at its face. */
426 template<typename T>
428  const VArray<T> &old_values,
429  MutableSpan<T> r_values)
430 {
431  BLI_assert(r_values.size() == mesh.totloop);
432 
433  threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange range) {
434  for (const int poly_index : range) {
435  const MPoly &poly = mesh.mpoly[poly_index];
436  MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop);
437  poly_corner_values.fill(old_values[poly_index]);
438  }
439  });
440 }
441 
443 {
444  GVArray new_varray;
445  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
446  using T = decltype(dummy);
447  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
448  Array<T> values(mesh.totloop);
449  adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray.typed<T>(), values);
450  new_varray = VArray<T>::ForContainer(std::move(values));
451  }
452  });
453  return new_varray;
454 }
455 
456 template<typename T>
458  const VArray<T> &old_values,
459  MutableSpan<T> r_values)
460 {
461  BLI_assert(r_values.size() == mesh.totedge);
462  attribute_math::DefaultMixer<T> mixer(r_values);
463 
464  for (const int poly_index : IndexRange(mesh.totpoly)) {
465  const MPoly &poly = mesh.mpoly[poly_index];
466  const T value = old_values[poly_index];
467  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
468  const MLoop &loop = mesh.mloop[loop_index];
469  mixer.mix_in(loop.e, value);
470  }
471  }
472  mixer.finalize();
473 }
474 
475 /* An edge is selected if any connected face was selected. */
476 template<>
478  const VArray<bool> &old_values,
479  MutableSpan<bool> r_values)
480 {
481  BLI_assert(r_values.size() == mesh.totedge);
482 
483  r_values.fill(false);
484  for (const int poly_index : IndexRange(mesh.totpoly)) {
485  const MPoly &poly = mesh.mpoly[poly_index];
486  if (old_values[poly_index]) {
487  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
488  const MLoop &loop = mesh.mloop[loop_index];
489  const int edge_index = loop.e;
490  r_values[edge_index] = true;
491  }
492  }
493  }
494 }
495 
497 {
498  GVArray new_varray;
499  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
500  using T = decltype(dummy);
501  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
502  Array<T> values(mesh.totedge);
503  adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray.typed<T>(), values);
504  new_varray = VArray<T>::ForContainer(std::move(values));
505  }
506  });
507  return new_varray;
508 }
509 
511 {
512  GVArray new_varray;
513  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
514  using T = decltype(dummy);
515  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
516  if constexpr (std::is_same_v<T, bool>) {
517  new_varray = VArray<T>::ForFunc(
518  mesh.totpoly, [&mesh, varray = varray.typed<bool>()](const int face_index) {
519  /* A face is selected if all of its vertices were selected. */
520  const MPoly &poly = mesh.mpoly[face_index];
521  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
522  const MLoop &loop = mesh.mloop[loop_index];
523  if (!varray[loop.v]) {
524  return false;
525  }
526  }
527  return true;
528  });
529  }
530  else {
531  new_varray = VArray<T>::ForFunc(
532  mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) {
533  T return_value;
534  attribute_math::DefaultMixer<T> mixer({&return_value, 1});
535  const MPoly &poly = mesh.mpoly[face_index];
536  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
537  const MLoop &loop = mesh.mloop[loop_index];
538  const T value = varray[loop.v];
539  mixer.mix_in(0, value);
540  }
541  mixer.finalize();
542  return return_value;
543  });
544  }
545  }
546  });
547  return new_varray;
548 }
549 
551 {
552  GVArray new_varray;
553  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
554  using T = decltype(dummy);
555  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
556  if constexpr (std::is_same_v<T, bool>) {
557  /* An edge is selected if both of its vertices were selected. */
558  new_varray = VArray<bool>::ForFunc(
559  mesh.totedge, [&mesh, varray = varray.typed<bool>()](const int edge_index) {
560  const MEdge &edge = mesh.medge[edge_index];
561  return varray[edge.v1] && varray[edge.v2];
562  });
563  }
564  else {
565  new_varray = VArray<T>::ForFunc(
566  mesh.totedge, [&mesh, varray = varray.typed<T>()](const int edge_index) {
567  T return_value;
568  attribute_math::DefaultMixer<T> mixer({&return_value, 1});
569  const MEdge &edge = mesh.medge[edge_index];
570  mixer.mix_in(0, varray[edge.v1]);
571  mixer.mix_in(0, varray[edge.v2]);
572  mixer.finalize();
573  return return_value;
574  });
575  }
576  }
577  });
578  return new_varray;
579 }
580 
581 template<typename T>
583  const VArray<T> &old_values,
584  MutableSpan<T> r_values)
585 {
586  BLI_assert(r_values.size() == mesh.totloop);
587  attribute_math::DefaultMixer<T> mixer(r_values);
588 
589  for (const int poly_index : IndexRange(mesh.totpoly)) {
590  const MPoly &poly = mesh.mpoly[poly_index];
591 
592  /* For every corner, mix the values from the adjacent edges on the face. */
593  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
594  const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop;
595  const MLoop &loop = mesh.mloop[loop_index];
596  const MLoop &loop_prev = mesh.mloop[loop_index_prev];
597  mixer.mix_in(loop_index, old_values[loop.e]);
598  mixer.mix_in(loop_index, old_values[loop_prev.e]);
599  }
600  }
601 
602  mixer.finalize();
603 }
604 
605 /* A corner is selected if its two adjacent edges were selected. */
606 template<>
608  const VArray<bool> &old_values,
609  MutableSpan<bool> r_values)
610 {
611  BLI_assert(r_values.size() == mesh.totloop);
612 
613  r_values.fill(false);
614 
615  for (const int poly_index : IndexRange(mesh.totpoly)) {
616  const MPoly &poly = mesh.mpoly[poly_index];
617  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
618  const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop;
619  const MLoop &loop = mesh.mloop[loop_index];
620  const MLoop &loop_prev = mesh.mloop[loop_index_prev];
621  if (old_values[loop.e] && old_values[loop_prev.e]) {
622  r_values[loop_index] = true;
623  }
624  }
625  }
626 }
627 
629 {
630  GVArray new_varray;
631  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
632  using T = decltype(dummy);
633  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
634  Array<T> values(mesh.totloop);
635  adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray.typed<T>(), values);
636  new_varray = VArray<T>::ForContainer(std::move(values));
637  }
638  });
639  return new_varray;
640 }
641 
642 template<typename T>
644  const VArray<T> &old_values,
645  MutableSpan<T> r_values)
646 {
647  BLI_assert(r_values.size() == mesh.totvert);
648  attribute_math::DefaultMixer<T> mixer(r_values);
649 
650  for (const int edge_index : IndexRange(mesh.totedge)) {
651  const MEdge &edge = mesh.medge[edge_index];
652  const T value = old_values[edge_index];
653  mixer.mix_in(edge.v1, value);
654  mixer.mix_in(edge.v2, value);
655  }
656 
657  mixer.finalize();
658 }
659 
660 /* A vertex is selected if any connected edge was selected. */
661 template<>
663  const VArray<bool> &old_values,
664  MutableSpan<bool> r_values)
665 {
666  BLI_assert(r_values.size() == mesh.totvert);
667 
668  r_values.fill(false);
669  for (const int edge_index : IndexRange(mesh.totedge)) {
670  const MEdge &edge = mesh.medge[edge_index];
671  if (old_values[edge_index]) {
672  r_values[edge.v1] = true;
673  r_values[edge.v2] = true;
674  }
675  }
676 }
677 
679 {
680  GVArray new_varray;
681  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
682  using T = decltype(dummy);
683  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
684  Array<T> values(mesh.totvert);
685  adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray.typed<T>(), values);
686  new_varray = VArray<T>::ForContainer(std::move(values));
687  }
688  });
689  return new_varray;
690 }
691 
693 {
694  GVArray new_varray;
695  attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
696  using T = decltype(dummy);
697  if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
698  if constexpr (std::is_same_v<T, bool>) {
699  /* A face is selected if all of its edges are selected. */
700  new_varray = VArray<bool>::ForFunc(
701  mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) {
702  const MPoly &poly = mesh.mpoly[face_index];
703  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
704  const MLoop &loop = mesh.mloop[loop_index];
705  if (!varray[loop.e]) {
706  return false;
707  }
708  }
709  return true;
710  });
711  }
712  else {
713  new_varray = VArray<T>::ForFunc(
714  mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) {
715  T return_value;
716  attribute_math::DefaultMixer<T> mixer({&return_value, 1});
717  const MPoly &poly = mesh.mpoly[face_index];
718  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
719  const MLoop &loop = mesh.mloop[loop_index];
720  const T value = varray[loop.e];
721  mixer.mix_in(0, value);
722  }
723  mixer.finalize();
724  return return_value;
725  });
726  }
727  }
728  });
729  return new_varray;
730 }
731 
732 } // namespace blender::bke
733 
735  const blender::GVArray &varray,
736  const eAttrDomain from_domain,
737  const eAttrDomain to_domain)
738 {
739  if (!varray) {
740  return {};
741  }
742  if (varray.size() == 0) {
743  return {};
744  }
745  if (from_domain == to_domain) {
746  return varray;
747  }
748 
749  switch (from_domain) {
750  case ATTR_DOMAIN_CORNER: {
751  switch (to_domain) {
752  case ATTR_DOMAIN_POINT:
754  case ATTR_DOMAIN_FACE:
756  case ATTR_DOMAIN_EDGE:
758  default:
759  break;
760  }
761  break;
762  }
763  case ATTR_DOMAIN_POINT: {
764  switch (to_domain) {
765  case ATTR_DOMAIN_CORNER:
767  case ATTR_DOMAIN_FACE:
769  case ATTR_DOMAIN_EDGE:
771  default:
772  break;
773  }
774  break;
775  }
776  case ATTR_DOMAIN_FACE: {
777  switch (to_domain) {
778  case ATTR_DOMAIN_POINT:
780  case ATTR_DOMAIN_CORNER:
782  case ATTR_DOMAIN_EDGE:
784  default:
785  break;
786  }
787  break;
788  }
789  case ATTR_DOMAIN_EDGE: {
790  switch (to_domain) {
791  case ATTR_DOMAIN_CORNER:
793  case ATTR_DOMAIN_POINT:
795  case ATTR_DOMAIN_FACE:
797  default:
798  break;
799  }
800  break;
801  }
802  default:
803  break;
804  }
805 
806  return {};
807 }
808 
809 namespace blender::bke {
810 
811 template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
812 static GVArray make_derived_read_attribute(const void *data, const int domain_num)
813 {
814  return VArray<ElemT>::template ForDerivedSpan<StructT, GetFunc>(
815  Span<StructT>((const StructT *)data, domain_num));
816 }
817 
818 template<typename StructT,
819  typename ElemT,
820  ElemT (*GetFunc)(const StructT &),
821  void (*SetFunc)(StructT &, ElemT)>
823 {
824  return VMutableArray<ElemT>::template ForDerivedSpan<StructT, GetFunc, SetFunc>(
825  MutableSpan<StructT>((StructT *)data, domain_num));
826 }
827 
828 static float3 get_vertex_position(const MVert &vert)
829 {
830  return float3(vert.co);
831 }
832 
833 static void set_vertex_position(MVert &vert, float3 position)
834 {
835  copy_v3_v3(vert.co, position);
836 }
837 
838 static void tag_component_positions_changed(void *owner)
839 {
840  Mesh *mesh = static_cast<Mesh *>(owner);
841  if (mesh != nullptr) {
843  }
844 }
845 
846 static int get_material_index(const MPoly &mpoly)
847 {
848  return static_cast<int>(mpoly.mat_nr);
849 }
850 
851 static void set_material_index(MPoly &mpoly, int index)
852 {
853  mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
854 }
855 
856 static bool get_shade_smooth(const MPoly &mpoly)
857 {
858  return mpoly.flag & ME_SMOOTH;
859 }
860 
861 static void set_shade_smooth(MPoly &mpoly, bool value)
862 {
863  SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH);
864 }
865 
866 static float2 get_loop_uv(const MLoopUV &uv)
867 {
868  return float2(uv.uv);
869 }
870 
871 static void set_loop_uv(MLoopUV &uv, float2 co)
872 {
873  copy_v2_v2(uv.uv, co);
874 }
875 
876 static float get_crease(const MEdge &edge)
877 {
878  return edge.crease / 255.0f;
879 }
880 
881 static void set_crease(MEdge &edge, float value)
882 {
883  edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
884 }
885 
887  private:
888  MDeformVert *dverts_;
889  const int dvert_index_;
890 
891  public:
892  VArrayImpl_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
893  : VMutableArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
894  {
895  }
896 
897  float get(const int64_t index) const override
898  {
899  if (dverts_ == nullptr) {
900  return 0.0f;
901  }
902  if (const MDeformWeight *weight = this->find_weight_at_index(index)) {
903  return weight->weight;
904  }
905  return 0.0f;
906  }
907 
908  void set(const int64_t index, const float value) override
909  {
910  MDeformVert &dvert = dverts_[index];
911  if (value == 0.0f) {
912  if (MDeformWeight *weight = this->find_weight_at_index(index)) {
913  weight->weight = 0.0f;
914  }
915  }
916  else {
917  MDeformWeight *weight = BKE_defvert_ensure_index(&dvert, dvert_index_);
918  weight->weight = value;
919  }
920  }
921 
922  void set_all(Span<float> src) override
923  {
924  for (const int64_t index : src.index_range()) {
925  this->set(index, src[index]);
926  }
927  }
928 
929  void materialize(IndexMask mask, MutableSpan<float> r_span) const override
930  {
931  if (dverts_ == nullptr) {
932  return r_span.fill_indices(mask, 0.0f);
933  }
934  for (const int64_t index : mask) {
935  if (const MDeformWeight *weight = this->find_weight_at_index(index)) {
936  r_span[index] = weight->weight;
937  }
938  else {
939  r_span[index] = 0.0f;
940  }
941  }
942  }
943 
945  {
946  this->materialize(mask, r_span);
947  }
948 
949  private:
950  MDeformWeight *find_weight_at_index(const int64_t index)
951  {
952  for (MDeformWeight &weight : MutableSpan(dverts_[index].dw, dverts_[index].totweight)) {
953  if (weight.def_nr == dvert_index_) {
954  return &weight;
955  }
956  }
957  return nullptr;
958  }
959  const MDeformWeight *find_weight_at_index(const int64_t index) const
960  {
961  for (const MDeformWeight &weight : Span(dverts_[index].dw, dverts_[index].totweight)) {
962  if (weight.def_nr == dvert_index_) {
963  return &weight;
964  }
965  }
966  return nullptr;
967  }
968 };
969 
974  public:
976  const AttributeIDRef &attribute_id) const final
977  {
978  if (!attribute_id.is_named()) {
979  return {};
980  }
981  const Mesh *mesh = static_cast<const Mesh *>(owner);
982  if (mesh == nullptr) {
983  return {};
984  }
985  const std::string name = attribute_id.name();
986  const int vertex_group_index = BLI_findstringindex(
987  &mesh->vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
988  if (vertex_group_index < 0) {
989  return {};
990  }
991  if (mesh->dvert == nullptr) {
992  static const float default_value = 0.0f;
993  return {VArray<float>::ForSingle(default_value, mesh->totvert), ATTR_DOMAIN_POINT};
994  }
996  mesh->dvert, mesh->totvert, vertex_group_index),
998  }
999 
1000  GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
1001  {
1002  if (!attribute_id.is_named()) {
1003  return {};
1004  }
1005  Mesh *mesh = static_cast<Mesh *>(owner);
1006  if (mesh == nullptr) {
1007  return {};
1008  }
1009 
1010  const std::string name = attribute_id.name();
1011  const int vertex_group_index = BLI_findstringindex(
1012  &mesh->vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
1013  if (vertex_group_index < 0) {
1014  return {};
1015  }
1016  if (mesh->dvert == nullptr) {
1018  }
1019  else {
1020  /* Copy the data layer if it is shared with some other mesh. */
1023  }
1025  mesh->dvert, mesh->totvert, vertex_group_index),
1027  }
1028 
1029  bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
1030  {
1031  if (!attribute_id.is_named()) {
1032  return false;
1033  }
1034  Mesh *mesh = static_cast<Mesh *>(owner);
1035  if (mesh == nullptr) {
1036  return true;
1037  }
1038 
1039  const std::string name = attribute_id.name();
1040 
1041  int index;
1042  bDeformGroup *group;
1043  if (!BKE_id_defgroup_name_find(&mesh->id, name.c_str(), &index, &group)) {
1044  return false;
1045  }
1047  MEM_freeN(group);
1048  if (mesh->dvert == nullptr) {
1049  return true;
1050  }
1051 
1052  /* Copy the data layer if it is shared with some other mesh. */
1055 
1056  for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) {
1057  MDeformWeight *weight = BKE_defvert_find_index(&dvert, index);
1058  BKE_defvert_remove_group(&dvert, weight);
1059  for (MDeformWeight &weight : MutableSpan(dvert.dw, dvert.totweight)) {
1060  if (weight.def_nr > index) {
1061  weight.def_nr--;
1062  }
1063  }
1064  }
1065  return true;
1066  }
1067 
1068  bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
1069  {
1070  const Mesh *mesh = static_cast<const Mesh *>(owner);
1071  if (mesh == nullptr) {
1072  return true;
1073  }
1074 
1076  if (!callback(group->name, {ATTR_DOMAIN_POINT, CD_PROP_FLOAT})) {
1077  return false;
1078  }
1079  }
1080  return true;
1081  }
1082 
1083  void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
1084  {
1086  }
1087 };
1088 
1093  public:
1096  "normal", ATTR_DOMAIN_FACE, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable)
1097  {
1098  }
1099 
1100  GVArray try_get_for_read(const void *owner) const final
1101  {
1102  const Mesh *mesh = static_cast<const Mesh *>(owner);
1103  if (mesh == nullptr || mesh->totpoly == 0) {
1104  return {};
1105  }
1107  }
1108 
1109  GAttributeWriter try_get_for_write(void *UNUSED(owner)) const final
1110  {
1111  return {};
1112  }
1113 
1114  bool try_delete(void *UNUSED(owner)) const final
1115  {
1116  return false;
1117  }
1118 
1119  bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
1120  {
1121  return false;
1122  }
1123 
1124  bool exists(const void *owner) const final
1125  {
1126  const Mesh *mesh = static_cast<const Mesh *>(owner);
1127  return mesh->totpoly != 0;
1128  }
1129 };
1130 
1136 {
1137  static auto update_custom_data_pointers = [](void *owner) {
1138  Mesh *mesh = static_cast<Mesh *>(owner);
1140  };
1141 
1142 #define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \
1143  [](void *owner) -> CustomData * { \
1144  Mesh *mesh = static_cast<Mesh *>(owner); \
1145  return &mesh->NAME; \
1146  }
1147 #define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \
1148  [](const void *owner) -> const CustomData * { \
1149  const Mesh *mesh = static_cast<const Mesh *>(owner); \
1150  return &mesh->NAME; \
1151  }
1152 #define MAKE_GET_ELEMENT_NUM_GETTER(NAME) \
1153  [](const void *owner) -> int { \
1154  const Mesh *mesh = static_cast<const Mesh *>(owner); \
1155  return mesh->NAME; \
1156  }
1157 
1158  static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata),
1160  MAKE_GET_ELEMENT_NUM_GETTER(totloop),
1161  update_custom_data_pointers};
1162  static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata),
1164  MAKE_GET_ELEMENT_NUM_GETTER(totvert),
1165  update_custom_data_pointers};
1166  static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata),
1168  MAKE_GET_ELEMENT_NUM_GETTER(totedge),
1169  update_custom_data_pointers};
1170  static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
1172  MAKE_GET_ELEMENT_NUM_GETTER(totpoly),
1173  update_custom_data_pointers};
1174 
1175 #undef MAKE_CONST_CUSTOM_DATA_GETTER
1176 #undef MAKE_MUTABLE_CUSTOM_DATA_GETTER
1177 
1178  static BuiltinCustomDataLayerProvider position(
1179  "position",
1182  CD_MVERT,
1186  point_access,
1187  make_derived_read_attribute<MVert, float3, get_vertex_position>,
1188  make_derived_write_attribute<MVert, float3, get_vertex_position, set_vertex_position>,
1190 
1192 
1193  static BuiltinCustomDataLayerProvider id("id",
1195  CD_PROP_INT32,
1196  CD_PROP_INT32,
1200  point_access,
1201  make_array_read_attribute<int>,
1202  make_array_write_attribute<int>,
1203  nullptr);
1204 
1205  static BuiltinCustomDataLayerProvider material_index(
1206  "material_index",
1208  CD_PROP_INT32,
1209  CD_MPOLY,
1213  face_access,
1214  make_derived_read_attribute<MPoly, int, get_material_index>,
1215  make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>,
1216  nullptr);
1217 
1218  static BuiltinCustomDataLayerProvider shade_smooth(
1219  "shade_smooth",
1221  CD_PROP_BOOL,
1222  CD_MPOLY,
1226  face_access,
1227  make_derived_read_attribute<MPoly, bool, get_shade_smooth>,
1228  make_derived_write_attribute<MPoly, bool, get_shade_smooth, set_shade_smooth>,
1229  nullptr);
1230 
1231  static BuiltinCustomDataLayerProvider crease(
1232  "crease",
1234  CD_PROP_FLOAT,
1235  CD_MEDGE,
1239  edge_access,
1240  make_derived_read_attribute<MEdge, float, get_crease>,
1241  make_derived_write_attribute<MEdge, float, get_crease, set_crease>,
1242  nullptr);
1243 
1244  static NamedLegacyCustomDataProvider uvs(
1247  CD_MLOOPUV,
1248  corner_access,
1249  make_derived_read_attribute<MLoopUV, float2, get_loop_uv>,
1250  make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv>);
1251 
1252  static VertexGroupsAttributeProvider vertex_groups;
1253  static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
1254  static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
1255  static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access);
1256  static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access);
1257 
1259  {&position, &id, &material_index, &shade_smooth, &normal, &crease},
1260  {&uvs,
1261  &corner_custom_data,
1262  &vertex_groups,
1263  &point_custom_data,
1264  &edge_custom_data,
1265  &face_custom_data});
1266 }
1267 
1269 {
1272  attribute_accessor_functions::accessor_functions_for_providers<providers>();
1273  fn.domain_size = [](const void *owner, const eAttrDomain domain) {
1274  if (owner == nullptr) {
1275  return 0;
1276  }
1277  const Mesh &mesh = *static_cast<const Mesh *>(owner);
1278  switch (domain) {
1279  case ATTR_DOMAIN_POINT:
1280  return mesh.totvert;
1281  case ATTR_DOMAIN_EDGE:
1282  return mesh.totedge;
1283  case ATTR_DOMAIN_FACE:
1284  return mesh.totpoly;
1285  case ATTR_DOMAIN_CORNER:
1286  return mesh.totloop;
1287  default:
1288  return 0;
1289  }
1290  };
1291  fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
1293  };
1294  fn.adapt_domain = [](const void *owner,
1295  const blender::GVArray &varray,
1296  const eAttrDomain from_domain,
1297  const eAttrDomain to_domain) -> blender::GVArray {
1298  if (owner == nullptr) {
1299  return {};
1300  }
1301  const Mesh &mesh = *static_cast<const Mesh *>(owner);
1302  return adapt_mesh_attribute_domain(mesh, varray, from_domain, to_domain);
1303  };
1304  return fn;
1305 }
1306 
1308 {
1310  return fn;
1311 }
1312 
1314 {
1316 }
1317 
1319 {
1321 }
1322 
1323 } // namespace blender::bke
1324 
1325 std::optional<blender::bke::AttributeAccessor> MeshComponent::attributes() const
1326 {
1328 }
1329 
1330 std::optional<blender::bke::MutableAttributeAccessor> MeshComponent::attributes_for_write()
1331 {
1332  Mesh *mesh = this->get_for_write();
1335 }
1336 
typedef float(TangentPoint)[2]
eAttrDomain
Definition: BKE_attribute.h:25
@ 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
void * CustomData_duplicate_referenced_layer(struct CustomData *data, int type, int totelem)
Definition: customdata.cc:2976
support for deformation groups and hooks.
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, int defgroup)
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup)
Definition: deform.c:748
bool BKE_id_defgroup_name_find(const struct ID *id, const char *name, int *r_index, struct bDeformGroup **r_group)
Definition: deform.c:517
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw)
Definition: deform.c:804
@ GEO_COMPONENT_TYPE_MESH
GeometryOwnershipType
void BKE_id_free(struct Main *bmain, void *idv)
struct Mesh * BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference)
const float(* BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3]
const float(* BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3]
void BKE_mesh_update_customdata_pointers(struct Mesh *me, bool do_ensure_tess_cd)
Definition: mesh.cc:874
void BKE_mesh_tag_coords_changed(struct Mesh *mesh)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define final(a, b, c)
Definition: BLI_hash.h:21
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
int BLI_findstringindex(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE unsigned char round_fl_to_uchar_clamp(float a)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_MDEFORMVERT
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_PROP_BOOL
@ CD_MEDGE
@ CD_MVERT
@ CD_MLOOPUV
@ ME_SMOOTH
Object is a sort of wrapper for general info.
bool is_mutable() const
Definition: geometry_set.cc:97
std::optional< blender::bke::MutableAttributeAccessor > attributes_for_write() final
const Mesh * get_for_read() const
bool is_empty() const final
void replace(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
std::optional< blender::bke::AttributeAccessor > attributes() const final
GeometryComponent * copy() const override
bool owns_direct_data() const override
void ensure_owns_direct_data() override
const CPPType & type() const
constexpr int64_t size() const
Definition: BLI_span.hh:511
constexpr void fill(const T &value)
Definition: BLI_span.hh:527
constexpr void fill_indices(Span< int64_t > indices, const T &value)
Definition: BLI_span.hh:536
static VArray ForContainer(ContainerT container)
static VArray ForSingle(T value, const int64_t size)
static VArray ForSpan(Span< T > values)
GAttributeWriter try_get_for_write(void *UNUSED(owner)) const final
GVArray try_get_for_read(const void *owner) const final
bool exists(const void *owner) const final
bool try_delete(void *UNUSED(owner)) const final
bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
float get(const int64_t index) const override
void set(const int64_t index, const float value) override
VArrayImpl_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
void materialize(IndexMask mask, MutableSpan< float > r_span) const override
void materialize_to_uninitialized(IndexMask mask, MutableSpan< float > r_span) const override
bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
GAttributeReader try_get_for_read(const void *owner, const AttributeIDRef &attribute_id) const final
void foreach_domain(const FunctionRef< void(eAttrDomain)> callback) const final
bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
DEGForeachIDComponentCallback callback
SyclQueue void void * src
#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME)
MDeformVert * BKE_object_defgroup_data_create(ID *id)
#define MAKE_GET_ELEMENT_NUM_GETTER(NAME)
#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME)
static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh, const blender::GVArray &varray, const eAttrDomain from_domain, const eAttrDomain to_domain)
IconTextureDrawCall normal
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
#define T
typename DefaultMixerStruct< T >::type DefaultMixer
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
static int domain_num(const CurvesGeometry &curves, const eAttrDomain domain)
static AttributeAccessorFunctions get_mesh_accessor_functions()
static float3 get_vertex_position(const MVert &vert)
static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &varray)
static void set_shade_smooth(MPoly &mpoly, bool value)
static GVArray make_derived_read_attribute(const void *data, const int domain_num)
static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray)
void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, const VArray< bool > &old_values, MutableSpan< bool > r_values)
static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray)
static float get_crease(const MEdge &edge)
void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, const VArray< bool > &old_values, MutableSpan< bool > r_values)
static void set_crease(MEdge &edge, float value)
static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &varray)
static void tag_component_positions_changed(void *owner)
void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, const VArray< bool > &old_values, MutableSpan< bool > r_values)
static void set_vertex_position(MVert &vert, float3 position)
static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray)
static GVMutableArray make_derived_write_attribute(void *data, const int domain_num)
static bool get_shade_smooth(const MPoly &mpoly)
static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray)
void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, const VArray< bool > &old_values, MutableSpan< bool > r_values)
static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray)
static GVArray adapt_mesh_domain_face_to_point(const Mesh &mesh, const GVArray &varray)
static void set_loop_uv(MLoopUV &uv, float2 co)
static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, const VArray< T > &old_values, MutableSpan< T > r_values)
static void set_material_index(MPoly &mpoly, int index)
VArray< float3 > mesh_normals_varray(const MeshComponent &mesh_component, const Mesh &mesh, const IndexMask mask, eAttrDomain domain)
static ComponentAttributeProviders create_attribute_providers_for_mesh()
static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray)
AttributeAccessor mesh_attributes(const Mesh &mesh)
void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, const VArray< bool > &old_values, MutableSpan< bool > r_values)
static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray)
static GVArray adapt_mesh_domain_edge_to_corner(const Mesh &mesh, const GVArray &varray)
void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, const VArray< T > &old_values, MutableSpan< T > r_values)
static const AttributeAccessorFunctions & get_mesh_accessor_functions_ref()
static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray)
static float2 get_loop_uv(const MLoopUV &uv)
MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
static int get_material_index(const MPoly &mpoly)
T clamp(const T &a, const T &min, const T &max)
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
T interpolate(const T &a, const T &b, const FactorT &t)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
vec_base< float, 3 > float3
vec_base< float, 2 > float2
__int64 int64_t
Definition: stdint.h:89
Definition: DNA_ID.h:368
unsigned int def_nr
unsigned int e
unsigned int v
short mat_nr
float co[3]
struct MEdge * medge
CustomData vdata
struct MDeformVert * dvert
int totedge
ListBase vertex_group_names
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
ustring name
Definition: graph/node.h:174
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)