Blender  V3.3
curve_to_mesh_convert.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_array.hh"
5 #include "BLI_set.hh"
6 #include "BLI_task.hh"
7 
8 #include "DNA_mesh_types.h"
9 #include "DNA_meshdata_types.h"
10 
11 #include "BKE_attribute_math.hh"
12 #include "BKE_curves.hh"
13 #include "BKE_geometry_set.hh"
14 #include "BKE_material.h"
15 #include "BKE_mesh.h"
16 
17 #include "BKE_curve_to_mesh.hh"
18 
19 namespace blender::bke {
20 
22 {
23  for (MEdge &edge : edges) {
24  edge.flag |= ME_SHARP;
25  }
26 }
27 
28 static void fill_mesh_topology(const int vert_offset,
29  const int edge_offset,
30  const int poly_offset,
31  const int loop_offset,
32  const int main_point_num,
33  const int profile_point_num,
34  const bool main_cyclic,
35  const bool profile_cyclic,
36  const bool fill_caps,
37  MutableSpan<MEdge> edges,
38  MutableSpan<MLoop> loops,
39  MutableSpan<MPoly> polys)
40 {
41  const int main_segment_num = curves::segments_num(main_point_num, main_cyclic);
42  const int profile_segment_num = curves::segments_num(profile_point_num, profile_cyclic);
43 
44  if (profile_point_num == 1) {
45  for (const int i : IndexRange(main_point_num - 1)) {
46  MEdge &edge = edges[edge_offset + i];
47  edge.v1 = vert_offset + i;
48  edge.v2 = vert_offset + i + 1;
49  edge.flag = ME_LOOSEEDGE;
50  }
51 
52  if (main_cyclic && main_segment_num > 1) {
53  MEdge &edge = edges[edge_offset + main_segment_num - 1];
54  edge.v1 = vert_offset + main_point_num - 1;
55  edge.v2 = vert_offset;
56  edge.flag = ME_LOOSEEDGE;
57  }
58  return;
59  }
60 
61  /* Add the edges running along the length of the curve, starting at each profile vertex. */
62  const int main_edges_start = edge_offset;
63  for (const int i_profile : IndexRange(profile_point_num)) {
64  const int profile_edge_offset = main_edges_start + i_profile * main_segment_num;
65  for (const int i_ring : IndexRange(main_segment_num)) {
66  const int i_next_ring = (i_ring == main_point_num - 1) ? 0 : i_ring + 1;
67 
68  const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
69  const int next_ring_vert_offset = vert_offset + profile_point_num * i_next_ring;
70 
71  MEdge &edge = edges[profile_edge_offset + i_ring];
72  edge.v1 = ring_vert_offset + i_profile;
73  edge.v2 = next_ring_vert_offset + i_profile;
74  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
75  }
76  }
77 
78  /* Add the edges running along each profile ring. */
79  const int profile_edges_start = main_edges_start + profile_point_num * main_segment_num;
80  for (const int i_ring : IndexRange(main_point_num)) {
81  const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
82 
83  const int ring_edge_offset = profile_edges_start + i_ring * profile_segment_num;
84  for (const int i_profile : IndexRange(profile_segment_num)) {
85  const int i_next_profile = (i_profile == profile_point_num - 1) ? 0 : i_profile + 1;
86 
87  MEdge &edge = edges[ring_edge_offset + i_profile];
88  edge.v1 = ring_vert_offset + i_profile;
89  edge.v2 = ring_vert_offset + i_next_profile;
90  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
91  }
92  }
93 
94  /* Calculate poly and corner indices. */
95  for (const int i_ring : IndexRange(main_segment_num)) {
96  const int i_next_ring = (i_ring == main_point_num - 1) ? 0 : i_ring + 1;
97 
98  const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
99  const int next_ring_vert_offset = vert_offset + profile_point_num * i_next_ring;
100 
101  const int ring_edge_start = profile_edges_start + profile_segment_num * i_ring;
102  const int next_ring_edge_offset = profile_edges_start + profile_segment_num * i_next_ring;
103 
104  const int ring_poly_offset = poly_offset + i_ring * profile_segment_num;
105  const int ring_loop_offset = loop_offset + i_ring * profile_segment_num * 4;
106 
107  for (const int i_profile : IndexRange(profile_segment_num)) {
108  const int ring_segment_loop_offset = ring_loop_offset + i_profile * 4;
109  const int i_next_profile = (i_profile == profile_point_num - 1) ? 0 : i_profile + 1;
110 
111  const int main_edge_start = main_edges_start + main_segment_num * i_profile;
112  const int next_main_edge_start = main_edges_start + main_segment_num * i_next_profile;
113 
114  MPoly &poly = polys[ring_poly_offset + i_profile];
115  poly.loopstart = ring_segment_loop_offset;
116  poly.totloop = 4;
117  poly.flag = ME_SMOOTH;
118 
119  MLoop &loop_a = loops[ring_segment_loop_offset];
120  loop_a.v = ring_vert_offset + i_profile;
121  loop_a.e = ring_edge_start + i_profile;
122  MLoop &loop_b = loops[ring_segment_loop_offset + 1];
123  loop_b.v = ring_vert_offset + i_next_profile;
124  loop_b.e = next_main_edge_start + i_ring;
125  MLoop &loop_c = loops[ring_segment_loop_offset + 2];
126  loop_c.v = next_ring_vert_offset + i_next_profile;
127  loop_c.e = next_ring_edge_offset + i_profile;
128  MLoop &loop_d = loops[ring_segment_loop_offset + 3];
129  loop_d.v = next_ring_vert_offset + i_profile;
130  loop_d.e = main_edge_start + i_ring;
131  }
132  }
133 
134  const bool has_caps = fill_caps && !main_cyclic && profile_cyclic && profile_point_num > 2;
135  if (has_caps) {
136  const int poly_num = main_segment_num * profile_segment_num;
137  const int cap_loop_offset = loop_offset + poly_num * 4;
138  const int cap_poly_offset = poly_offset + poly_num;
139 
140  MPoly &poly_start = polys[cap_poly_offset];
141  poly_start.loopstart = cap_loop_offset;
142  poly_start.totloop = profile_segment_num;
143  MPoly &poly_end = polys[cap_poly_offset + 1];
144  poly_end.loopstart = cap_loop_offset + profile_segment_num;
145  poly_end.totloop = profile_segment_num;
146 
147  const int last_ring_index = main_point_num - 1;
148  const int last_ring_vert_offset = vert_offset + profile_point_num * last_ring_index;
149  const int last_ring_edge_offset = profile_edges_start + profile_segment_num * last_ring_index;
150 
151  for (const int i : IndexRange(profile_segment_num)) {
152  const int i_inv = profile_segment_num - i - 1;
153  MLoop &loop_start = loops[cap_loop_offset + i];
154  loop_start.v = vert_offset + i_inv;
155  loop_start.e = profile_edges_start +
156  ((i == (profile_segment_num - 1)) ? (profile_segment_num - 1) : (i_inv - 1));
157  MLoop &loop_end = loops[cap_loop_offset + profile_segment_num + i];
158  loop_end.v = last_ring_vert_offset + i;
159  loop_end.e = last_ring_edge_offset + i;
160  }
161 
162  mark_edges_sharp(edges.slice(profile_edges_start, profile_segment_num));
163  mark_edges_sharp(edges.slice(last_ring_edge_offset, profile_segment_num));
164  }
165 }
166 
167 static void mark_bezier_vector_edges_sharp(const int profile_point_num,
168  const int main_segment_num,
169  const Span<int> control_point_offsets,
170  const Span<int8_t> handle_types_left,
171  const Span<int8_t> handle_types_right,
172  MutableSpan<MEdge> edges)
173 {
174  const int main_edges_start = 0;
175  if (curves::bezier::point_is_sharp(handle_types_left, handle_types_right, 0)) {
176  mark_edges_sharp(edges.slice(main_edges_start, main_segment_num));
177  }
178 
179  for (const int i : IndexRange(profile_point_num).drop_front(1)) {
180  if (curves::bezier::point_is_sharp(handle_types_left, handle_types_right, i)) {
181  mark_edges_sharp(edges.slice(
182  main_edges_start + main_segment_num * control_point_offsets[i - 1], main_segment_num));
183  }
184  }
185 }
186 
187 static void fill_mesh_positions(const int main_point_num,
188  const int profile_point_num,
189  const Span<float3> main_positions,
190  const Span<float3> profile_positions,
191  const Span<float3> tangents,
192  const Span<float3> normals,
193  const Span<float> radii,
194  MutableSpan<MVert> mesh_positions)
195 {
196  if (profile_point_num == 1) {
197  for (const int i_ring : IndexRange(main_point_num)) {
199  main_positions[i_ring], normals[i_ring], tangents[i_ring]);
200  if (!radii.is_empty()) {
201  point_matrix.apply_scale(radii[i_ring]);
202  }
203 
204  MVert &vert = mesh_positions[i_ring];
205  copy_v3_v3(vert.co, point_matrix * profile_positions.first());
206  }
207  }
208  else {
209  for (const int i_ring : IndexRange(main_point_num)) {
211  main_positions[i_ring], normals[i_ring], tangents[i_ring]);
212  if (!radii.is_empty()) {
213  point_matrix.apply_scale(radii[i_ring]);
214  }
215 
216  const int ring_vert_start = i_ring * profile_point_num;
217  for (const int i_profile : IndexRange(profile_point_num)) {
218  MVert &vert = mesh_positions[ring_vert_start + i_profile];
219  copy_v3_v3(vert.co, point_matrix * profile_positions[i_profile]);
220  }
221  }
222  }
223 }
224 
225 struct CurvesInfo {
228 
229  /* Make sure these are spans because they are potentially accessed many times. */
232 };
234 {
235  return {main, profile, main.cyclic(), profile.cyclic()};
236 }
237 
240  int total;
241 
247 
248  /* The indices of the main and profile curves that form each combination. */
251 };
252 static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool fill_caps)
253 {
255  result.total = info.main.curves_num() * info.profile.curves_num();
256  result.vert.reinitialize(result.total + 1);
257  result.edge.reinitialize(result.total + 1);
258  result.loop.reinitialize(result.total + 1);
259  result.poly.reinitialize(result.total + 1);
260 
261  result.main_indices.reinitialize(result.total);
262  result.profile_indices.reinitialize(result.total);
263 
266 
267  int mesh_index = 0;
268  int vert_offset = 0;
269  int edge_offset = 0;
270  int loop_offset = 0;
271  int poly_offset = 0;
272  for (const int i_main : info.main.curves_range()) {
273  const bool main_cyclic = info.main_cyclic[i_main];
274  const int main_point_num = info.main.evaluated_points_for_curve(i_main).size();
275  const int main_segment_num = curves::segments_num(main_point_num, main_cyclic);
276  for (const int i_profile : info.profile.curves_range()) {
277  result.vert[mesh_index] = vert_offset;
278  result.edge[mesh_index] = edge_offset;
279  result.loop[mesh_index] = loop_offset;
280  result.poly[mesh_index] = poly_offset;
281 
282  result.main_indices[mesh_index] = i_main;
283  result.profile_indices[mesh_index] = i_profile;
284 
285  const bool profile_cyclic = info.profile_cyclic[i_profile];
286  const int profile_point_num = info.profile.evaluated_points_for_curve(i_profile).size();
287  const int profile_segment_num = curves::segments_num(profile_point_num, profile_cyclic);
288 
289  const bool has_caps = fill_caps && !main_cyclic && profile_cyclic && profile_point_num > 2;
290  const int tube_face_num = main_segment_num * profile_segment_num;
291 
292  vert_offset += main_point_num * profile_point_num;
293 
294  /* Add the ring edges, with one ring for every curve vertex, and the edge loops
295  * that run along the length of the curve, starting on the first profile. */
296  edge_offset += main_point_num * profile_segment_num + main_segment_num * profile_point_num;
297 
298  /* Add two cap N-gons for every ending. */
299  poly_offset += tube_face_num + (has_caps ? 2 : 0);
300 
301  /* All faces on the tube are quads, and all cap faces are N-gons with an edge for each
302  * profile edge. */
303  loop_offset += tube_face_num * 4 + (has_caps ? profile_segment_num * 2 : 0);
304 
305  mesh_index++;
306  }
307  }
308 
309  result.vert.last() = vert_offset;
310  result.edge.last() = edge_offset;
311  result.loop.last() = loop_offset;
312  result.poly.last() = poly_offset;
313 
314  return result;
315 }
316 
318  const AttributeIDRef &attribute_id)
319 {
320  /* Only use a different domain if it is builtin and must only exist on one domain. */
321  if (!mesh_attributes.is_builtin(attribute_id)) {
322  return ATTR_DOMAIN_POINT;
323  }
324 
325  std::optional<AttributeMetaData> meta_data = mesh_attributes.lookup_meta_data(attribute_id);
326  if (!meta_data) {
327  return ATTR_DOMAIN_POINT;
328  }
329 
330  return meta_data->domain;
331 }
332 
333 static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes,
335  const AttributeIDRef &id)
336 {
337 
338  /* The position attribute has special non-generic evaluation. */
339  if (id.is_named() && id.name() == "position") {
340  return false;
341  }
342  /* Don't propagate built-in curves attributes that are not built-in on meshes. */
343  if (curve_attributes.is_builtin(id) && !mesh_attributes.is_builtin(id)) {
344  return false;
345  }
346  if (!id.should_be_kept()) {
347  return false;
348  }
349  return true;
350 }
351 
353  const CurvesGeometry &curves,
354  const std::array<int, CURVE_TYPES_NUM> &type_counts,
356 {
357  if (type_counts[CURVE_TYPE_POLY] == curves.curves_num() && src.is_span()) {
358  return src.get_internal_span();
359  }
360  buffer.reinitialize(curves.evaluated_points_num() * src.type().size());
361  GMutableSpan eval{src.type(), buffer.data(), curves.evaluated_points_num()};
362  curves.interpolate_to_evaluated(src.get_internal_span(), eval);
363  return eval;
364 }
365 
368  int i_main;
370 
373 
376 
379 
384 };
385 template<typename Fn>
386 static void foreach_curve_combination(const CurvesInfo &info,
387  const ResultOffsets &offsets,
388  const Fn &fn)
389 {
390  threading::parallel_for(IndexRange(offsets.total), 512, [&](IndexRange range) {
391  for (const int i : range) {
392  const int i_main = offsets.main_indices[i];
393  const int i_profile = offsets.profile_indices[i];
394 
395  const IndexRange main_points = info.main.evaluated_points_for_curve(i_main);
396  const IndexRange profile_points = info.profile.evaluated_points_for_curve(i_profile);
397 
398  const bool main_cyclic = info.main_cyclic[i_main];
399  const bool profile_cyclic = info.profile_cyclic[i_profile];
400 
401  /* Pass all information in a struct to avoid repeating arguments in many lambdas.
402  * The idea is that inlining `fn` will help avoid accessing unnecessary information,
403  * though that may or may not happen in practice. */
404  fn(CombinationInfo{i_main,
405  i_profile,
406  main_points,
407  profile_points,
408  main_cyclic,
409  profile_cyclic,
410  curves::segments_num(main_points.size(), main_cyclic),
411  curves::segments_num(profile_points.size(), profile_cyclic),
412  offsets_to_range(offsets.vert.as_span(), i),
413  offsets_to_range(offsets.edge.as_span(), i),
414  offsets_to_range(offsets.poly.as_span(), i),
415  offsets_to_range(offsets.loop.as_span(), i)});
416  }
417  });
418 }
419 
420 template<typename T>
422  const int profile_point_num,
423  MutableSpan<T> dst)
424 {
425  for (const int i_ring : src.index_range()) {
426  const int ring_vert_start = i_ring * profile_point_num;
427  dst.slice(ring_vert_start, profile_point_num).fill(src[i_ring]);
428  }
429 }
430 
431 template<typename T>
433  const int profile_point_num,
434  const int main_segment_num,
435  const int profile_segment_num,
436  MutableSpan<T> dst)
437 {
438  const int edges_start = profile_point_num * main_segment_num;
439  for (const int i_ring : src.index_range()) {
440  const int ring_edge_start = edges_start + profile_segment_num * i_ring;
441  dst.slice(ring_edge_start, profile_segment_num).fill(src[i_ring]);
442  }
443 }
444 
445 template<typename T>
447  const int main_segment_num,
448  const int profile_segment_num,
449  MutableSpan<T> dst)
450 {
451  for (const int i_ring : IndexRange(main_segment_num)) {
452  const int ring_face_start = profile_segment_num * i_ring;
453  dst.slice(ring_face_start, profile_segment_num).fill(src[i_ring]);
454  }
455 }
456 
458  const ResultOffsets &offsets,
459  const eAttrDomain dst_domain,
460  const GSpan src_all,
461  GMutableSpan dst_all)
462 {
463  attribute_math::convert_to_static_type(src_all.type(), [&](auto dummy) {
464  using T = decltype(dummy);
465  const Span<T> src = src_all.typed<T>();
466  MutableSpan<T> dst = dst_all.typed<T>();
467  switch (dst_domain) {
468  case ATTR_DOMAIN_POINT:
469  foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
470  copy_main_point_data_to_mesh_verts(
471  src.slice(info.main_points), info.profile_points.size(), dst.slice(info.vert_range));
472  });
473  break;
474  case ATTR_DOMAIN_EDGE:
475  foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
476  copy_main_point_data_to_mesh_edges(src.slice(info.main_points),
477  info.profile_points.size(),
478  info.main_segment_num,
479  info.profile_segment_num,
480  dst.slice(info.edge_range));
481  });
482  break;
483  case ATTR_DOMAIN_FACE:
484  foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
485  copy_main_point_data_to_mesh_faces(src.slice(info.main_points),
486  info.main_segment_num,
487  info.profile_segment_num,
488  dst.slice(info.poly_range));
489  });
490  break;
491  case ATTR_DOMAIN_CORNER:
492  /* Unsupported for now, since there are no builtin attributes to convert into. */
493  break;
494  default:
495  BLI_assert_unreachable();
496  break;
497  }
498  });
499 }
500 
501 template<typename T>
503  const int main_point_num,
504  MutableSpan<T> dst)
505 {
506  for (const int i_ring : IndexRange(main_point_num)) {
507  const int profile_vert_start = i_ring * src.size();
508  for (const int i_profile : src.index_range()) {
509  dst[profile_vert_start + i_profile] = src[i_profile];
510  }
511  }
512 }
513 
514 template<typename T>
516  const int main_segment_num,
517  MutableSpan<T> dst)
518 {
519  for (const int i_profile : src.index_range()) {
520  const int profile_edge_offset = i_profile * main_segment_num;
521  dst.slice(profile_edge_offset, main_segment_num).fill(src[i_profile]);
522  }
523 }
524 
525 template<typename T>
527  const int main_segment_num,
528  const int profile_segment_num,
529  MutableSpan<T> dst)
530 {
531  for (const int i_ring : IndexRange(main_segment_num)) {
532  const int profile_face_start = i_ring * profile_segment_num;
533  for (const int i_profile : IndexRange(profile_segment_num)) {
534  dst[profile_face_start + i_profile] = src[i_profile];
535  }
536  }
537 }
538 
540  const ResultOffsets &offsets,
541  const eAttrDomain dst_domain,
542  const GSpan src_all,
543  GMutableSpan dst_all)
544 {
545  attribute_math::convert_to_static_type(src_all.type(), [&](auto dummy) {
546  using T = decltype(dummy);
547  const Span<T> src = src_all.typed<T>();
548  MutableSpan<T> dst = dst_all.typed<T>();
549  switch (dst_domain) {
550  case ATTR_DOMAIN_POINT:
551  foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
552  copy_profile_point_data_to_mesh_verts(
553  src.slice(info.profile_points), info.main_points.size(), dst.slice(info.vert_range));
554  });
555  break;
556  case ATTR_DOMAIN_EDGE:
557  foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
558  copy_profile_point_data_to_mesh_edges(
559  src.slice(info.profile_points), info.main_segment_num, dst.slice(info.edge_range));
560  });
561  break;
562  case ATTR_DOMAIN_FACE:
563  foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
564  copy_profile_point_data_to_mesh_faces(src.slice(info.profile_points),
565  info.main_segment_num,
566  info.profile_segment_num,
567  dst.slice(info.poly_range));
568  });
569  break;
570  case ATTR_DOMAIN_CORNER:
571  /* Unsupported for now, since there are no builtin attributes to convert into. */
572  break;
573  default:
574  BLI_assert_unreachable();
575  break;
576  }
577  });
578 }
579 
580 template<typename T>
582  const Span<int> curve_indices,
583  const Span<int> mesh_offsets,
584  MutableSpan<T> dst)
585 {
586  /* This unnecessarily instantiates the "is single" case (which should be handled elsewhere if
587  * it's ever used for attributes), but the alternative is duplicating the function for spans and
588  * other virtual arrays. */
589  devirtualize_varray(src, [&](const auto &src) {
590  threading::parallel_for(curve_indices.index_range(), 512, [&](IndexRange range) {
591  for (const int i : range) {
592  dst.slice(offsets_to_range(mesh_offsets, i)).fill(src[curve_indices[i]]);
593  }
594  });
595  });
596 }
597 
598 static void copy_curve_domain_attribute_to_mesh(const ResultOffsets &mesh_offsets,
599  const Span<int> curve_indices,
600  const eAttrDomain dst_domain,
601  const GVArray &src,
602  GMutableSpan dst)
603 {
604  Span<int> offsets;
605  switch (dst_domain) {
606  case ATTR_DOMAIN_POINT:
607  offsets = mesh_offsets.vert;
608  break;
609  case ATTR_DOMAIN_EDGE:
610  offsets = mesh_offsets.edge;
611  break;
612  case ATTR_DOMAIN_FACE:
613  offsets = mesh_offsets.poly;
614  break;
615  case ATTR_DOMAIN_CORNER:
616  offsets = mesh_offsets.loop;
617  break;
618  default:
620  return;
621  }
622  attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
623  using T = decltype(dummy);
624  copy_indices_to_offset_ranges(src.typed<T>(), curve_indices, offsets, dst.typed<T>());
625  });
626 }
627 
629  const CurvesGeometry &profile,
630  const bool fill_caps)
631 {
632  const CurvesInfo curves_info = get_curves_info(main, profile);
633 
634  const ResultOffsets offsets = calculate_result_offsets(curves_info, fill_caps);
635  if (offsets.vert.last() == 0) {
636  return nullptr;
637  }
638 
640  offsets.vert.last(), offsets.edge.last(), 0, offsets.loop.last(), offsets.poly.last());
641  mesh->flag |= ME_AUTOSMOOTH;
642  mesh->smoothresh = DEG2RADF(180.0f);
647 
648  foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
650  info.edge_range.start(),
651  info.poly_range.start(),
652  info.loop_range.start(),
653  info.main_points.size(),
654  info.profile_points.size(),
655  info.main_cyclic,
656  info.profile_cyclic,
657  fill_caps,
658  edges,
659  loops,
660  polys);
661  });
662 
663  const Span<float3> main_positions = main.evaluated_positions();
664  const Span<float3> tangents = main.evaluated_tangents();
665  const Span<float3> normals = main.evaluated_normals();
666  const Span<float3> profile_positions = profile.evaluated_positions();
667 
668  Vector<std::byte> eval_buffer;
669 
670  const AttributeAccessor main_attributes = main.attributes();
671  const AttributeAccessor profile_attributes = profile.attributes();
672 
673  Span<float> radii = {};
674  if (main_attributes.contains("radius")) {
676  main_attributes.lookup_or_default<float>("radius", ATTR_DOMAIN_POINT, 1.0f),
677  main,
678  main.curve_type_counts(),
679  eval_buffer)
680  .typed<float>();
681  }
682 
683  foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
685  info.profile_points.size(),
686  main_positions.slice(info.main_points),
687  profile_positions.slice(info.profile_points),
688  tangents.slice(info.main_points),
689  normals.slice(info.main_points),
690  radii.is_empty() ? radii : radii.slice(info.main_points),
691  verts.slice(info.vert_range));
692  });
693 
694  if (profile.curve_type_counts()[CURVE_TYPE_BEZIER] > 0) {
695  const VArray<int8_t> curve_types = profile.curve_types();
696  const VArraySpan<int8_t> handle_types_left{profile.handle_types_left()};
697  const VArraySpan<int8_t> handle_types_right{profile.handle_types_right()};
698 
699  foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
700  if (curve_types[info.i_profile] == CURVE_TYPE_BEZIER) {
701  const IndexRange points = profile.points_for_curve(info.i_profile);
702  mark_bezier_vector_edges_sharp(points.size(),
703  info.main_segment_num,
704  profile.bezier_evaluated_offsets_for_curve(info.i_profile),
705  handle_types_left.slice(points),
706  handle_types_right.slice(points),
707  edges.slice(info.edge_range));
708  }
709  });
710  }
711 
712  Set<AttributeIDRef> main_attributes_set;
713 
715 
716  main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
717  if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id)) {
718  return true;
719  }
720  main_attributes_set.add_new(id);
721 
722  const eAttrDomain src_domain = meta_data.domain;
723  const eCustomDataType type = meta_data.data_type;
724  GVArray src = main_attributes.lookup(id, src_domain, type);
725 
727  GSpanAttributeWriter dst = mesh_attributes.lookup_or_add_for_write_only_span(
728  id, dst_domain, type);
729  if (!dst) {
730  return true;
731  }
732 
733  if (src_domain == ATTR_DOMAIN_POINT) {
735  curves_info,
736  offsets,
737  dst_domain,
738  evaluated_attribute_if_necessary(src, main, main.curve_type_counts(), eval_buffer),
739  dst.span);
740  }
741  else if (src_domain == ATTR_DOMAIN_CURVE) {
743  offsets, offsets.main_indices, dst_domain, src, dst.span);
744  }
745 
746  dst.finish();
747  return true;
748  });
749 
750  profile_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
751  if (main_attributes.contains(id)) {
752  return true;
753  }
754  if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id)) {
755  return true;
756  }
757  const eAttrDomain src_domain = meta_data.domain;
758  const eCustomDataType type = meta_data.data_type;
759  GVArray src = profile_attributes.lookup(id, src_domain, type);
760 
762  GSpanAttributeWriter dst = mesh_attributes.lookup_or_add_for_write_only_span(
763  id, dst_domain, type);
764  if (!dst) {
765  return true;
766  }
767 
768  if (src_domain == ATTR_DOMAIN_POINT) {
770  curves_info,
771  offsets,
772  dst_domain,
773  evaluated_attribute_if_necessary(src, profile, profile.curve_type_counts(), eval_buffer),
774  dst.span);
775  }
776  else if (src_domain == ATTR_DOMAIN_CURVE) {
778  offsets, offsets.profile_indices, dst_domain, src, dst.span);
779  }
780 
781  dst.finish();
782  return true;
783  });
784 
785  return mesh;
786 }
787 
789 {
790  CurvesGeometry curves(1, 1);
791  curves.offsets_for_write().last() = 1;
792  curves.positions_for_write().fill(float3(0));
793  curves.fill_curve_types(CURVE_TYPE_POLY);
794 
795  return curves;
796 }
797 
799 {
800  static const CurvesGeometry vert_curve = get_curve_single_vert();
801  return curve_to_mesh_sweep(curve, vert_curve, false);
802 }
803 
804 } // namespace blender::bke
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_CURVE
Definition: BKE_attribute.h:31
@ 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
Low-level operations for curves.
General operations, lookup, etc. for materials.
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.cc:991
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define DEG2RADF(_deg)
MINLINE void copy_v3_v3(float r[3], const float a[3])
@ CURVE_TYPE_BEZIER
@ CURVE_TYPE_POLY
eCustomDataType
@ ME_AUTOSMOOTH
@ ME_SMOOTH
@ ME_EDGEDRAW
@ ME_EDGERENDER
@ ME_LOOSEEDGE
@ ME_SHARP
_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
float float3[3]
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
int main(int argc, char *argv[])
const T & last(const int64_t n=0) const
Definition: BLI_array.hh:284
const CPPType & type() const
Span< T > typed() const
constexpr int64_t size() const
constexpr int64_t start() const
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
void add_new(const Key &key)
Definition: BLI_set.hh:238
constexpr Span slice(int64_t start, int64_t size) const
Definition: BLI_span.hh:142
constexpr const T & first() const
Definition: BLI_span.hh:303
constexpr IndexRange index_range() const
Definition: BLI_span.hh:401
bool is_builtin(const AttributeIDRef &attribute_id) const
bool contains(const AttributeIDRef &attribute_id) const
std::optional< AttributeMetaData > lookup_meta_data(const AttributeIDRef &attribute_id) const
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
GVArray lookup_or_default(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const void *default_value=nullptr) const
bool for_all(const AttributeForeachCallback fn) const
IndexRange evaluated_points_for_curve(int index) const
Definition: BKE_curves.hh:848
VArray< int8_t > handle_types_left() const
VArray< int8_t > handle_types_right() const
IndexRange curves_range() const
Definition: BKE_curves.hh:795
const std::array< int, CURVE_TYPES_NUM > & curve_type_counts() const
Definition: BKE_curves.hh:816
AttributeAccessor attributes() const
Span< float3 > evaluated_positions() const
VArray< int8_t > curve_types() const
Curve curve
SyclQueue void void * src
static float verts[][3]
ccl_global float * buffer
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
bool point_is_sharp(Span< int8_t > handle_types_left, Span< int8_t > handle_types_right, int index)
Definition: BKE_curves.hh:904
int segments_num(const int points_num, const bool cyclic)
Definition: BKE_curves.hh:462
Mesh * curve_to_wire_mesh(const CurvesGeometry &curve)
static void copy_main_point_data_to_mesh_verts(const Span< T > src, const int profile_point_num, MutableSpan< T > dst)
static void mark_bezier_vector_edges_sharp(const int profile_point_num, const int main_segment_num, const Span< int > control_point_offsets, const Span< int8_t > handle_types_left, const Span< int8_t > handle_types_right, MutableSpan< MEdge > edges)
static void copy_main_point_domain_attribute_to_mesh(const CurvesInfo &curves_info, const ResultOffsets &offsets, const eAttrDomain dst_domain, const GSpan src_all, GMutableSpan dst_all)
Mesh * curve_to_mesh_sweep(const CurvesGeometry &main, const CurvesGeometry &profile, bool fill_caps)
static void copy_profile_point_domain_attribute_to_mesh(const CurvesInfo &curves_info, const ResultOffsets &offsets, const eAttrDomain dst_domain, const GSpan src_all, GMutableSpan dst_all)
static void mark_edges_sharp(MutableSpan< MEdge > edges)
static CurvesInfo get_curves_info(const CurvesGeometry &main, const CurvesGeometry &profile)
static void copy_profile_point_data_to_mesh_edges(const Span< T > src, const int main_segment_num, MutableSpan< T > dst)
static void fill_mesh_topology(const int vert_offset, const int edge_offset, const int poly_offset, const int loop_offset, const int main_point_num, const int profile_point_num, const bool main_cyclic, const bool profile_cyclic, const bool fill_caps, MutableSpan< MEdge > edges, MutableSpan< MLoop > loops, MutableSpan< MPoly > polys)
static eAttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_attributes, const AttributeIDRef &attribute_id)
static CurvesGeometry get_curve_single_vert()
static void copy_main_point_data_to_mesh_faces(const Span< T > src, const int main_segment_num, const int profile_segment_num, MutableSpan< T > dst)
static void foreach_curve_combination(const CurvesInfo &info, const ResultOffsets &offsets, const Fn &fn)
static GSpan evaluated_attribute_if_necessary(const GVArray &src, const CurvesGeometry &curves, const std::array< int, CURVE_TYPES_NUM > &type_counts, Vector< std::byte > &buffer)
static void copy_curve_domain_attribute_to_mesh(const ResultOffsets &mesh_offsets, const Span< int > curve_indices, const eAttrDomain dst_domain, const GVArray &src, GMutableSpan dst)
static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool fill_caps)
static void copy_profile_point_data_to_mesh_verts(const Span< T > src, const int main_point_num, MutableSpan< T > dst)
static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes, const AttributeAccessor &mesh_attributes, const AttributeIDRef &id)
static void copy_indices_to_offset_ranges(const VArray< T > &src, const Span< int > curve_indices, const Span< int > mesh_offsets, MutableSpan< T > dst)
static void copy_main_point_data_to_mesh_edges(const Span< T > src, const int profile_point_num, const int main_segment_num, const int profile_segment_num, MutableSpan< T > dst)
static void fill_mesh_positions(const int main_point_num, const int profile_point_num, const Span< float3 > main_positions, const Span< float3 > profile_positions, const Span< float3 > tangents, const Span< float3 > normals, const Span< float > radii, MutableSpan< MVert > mesh_positions)
AttributeAccessor mesh_attributes(const Mesh &mesh)
MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
static void copy_profile_point_data_to_mesh_faces(const Span< T > src, const int main_segment_num, const int profile_segment_num, MutableSpan< T > dst)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
void devirtualize_varray(const VArray< T > &varray, const Func &func, bool enable=true)
MutableSpan< float > radii
MutableSpan< float3 > tangents
MutableSpan< float3 > normals
unsigned int e
unsigned int v
float co[3]
struct MEdge * medge
float smoothresh
struct MVert * mvert
uint16_t flag
int totedge
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
const CurvesGeometry & profile
const CurvesGeometry & main
void apply_scale(const float scale)
static float4x4 from_normalized_axis_data(const float3 location, const float3 forward, const float3 up)
Definition: BLI_float4x4.hh:43