152 const int target_start,
153 const int target_verts_num,
154 const int source_start,
155 const int source_verts_num,
159 int i_source, i_target, i_target_low_bound, target_end, source_end;
160 SortVertsElem *sve_source, *sve_target, *sve_target_low_bound;
161 bool target_scan_completed;
163 target_end = target_start + target_verts_num;
164 source_end = source_start + source_verts_num;
173 svert_from_mvert(sorted_verts_target, vert_positions, target_start, target_end);
176 svert_from_mvert(sorted_verts_source, vert_positions, source_start, source_end);
182 sve_target_low_bound = sorted_verts_target;
183 i_target_low_bound = 0;
184 target_scan_completed =
false;
188 for (i_source = 0, sve_source = sorted_verts_source; i_source < source_verts_num;
189 i_source++, sve_source++)
191 int best_target_vertex = -1;
192 float best_dist_sq = dist * dist;
193 float sve_source_sumco;
196 if (doubles_map[sve_source->
vertex_num] != -1) {
201 if (target_scan_completed) {
206 sve_source_sumco =
sum_v3(sve_source->
co);
210 while ((i_target_low_bound < target_verts_num) &&
211 (sve_target_low_bound->
sum_co < sve_source_sumco - dist3))
213 i_target_low_bound++;
214 sve_target_low_bound++;
217 if (i_target_low_bound >= target_verts_num) {
219 target_scan_completed =
true;
224 i_target = i_target_low_bound;
225 sve_target = sve_target_low_bound;
230 while ((i_target < target_verts_num) && (sve_target->
sum_co <= sve_source_sumco + dist3)) {
236 best_dist_sq = dist_sq;
244 while (best_target_vertex != -1 &&
245 !
ELEM(doubles_map[best_target_vertex], -1, best_target_vertex))
248 vert_positions[doubles_map[best_target_vertex]],
251 best_target_vertex = doubles_map[best_target_vertex];
254 best_target_vertex = -1;
262 doubles_map[sve_source->
vertex_num] = best_target_vertex;
271 const float cap_offset[4][4],
272 uint cap_verts_index,
273 uint cap_edges_index,
298 &cap_mesh->
corner_data, &result->corner_data, 0, cap_loops_index, cap_nloops);
301 for (i = 0; i < cap_nverts; i++) {
302 mul_m4_v3(cap_offset, result_positions[cap_verts_index + i]);
307 for (i = 0; i < cap_nverts; i++) {
308 mul_mat3_m4_v3(cap_offset, dst_vert_normals[cap_verts_index + i]);
314 if (!result->deform_verts().is_empty()) {
315 MDeformVert *dvert = result->deform_verts_for_write().data();
320 edge = &result_edges[cap_edges_index];
321 for (i = 0; i < cap_nedges; i++, edge++) {
322 (*edge) += cap_verts_index;
326 for (i = 0; i < cap_nfaces; i++) {
327 result_face_offsets[cap_faces_index + i] = cap_face_offsets[i] + cap_loops_index;
331 for (i = 0; i < cap_nloops; i++) {
332 result_corner_verts[cap_loops_index + i] += cap_verts_index;
333 result_corner_edges[cap_loops_index + i] += cap_edges_index;
337 if (
const VArray cap_material_indices = *cap_attributes.
lookup<
int>(
"material_index",
338 bke::AttrDomain::Face))
343 bke::AttrDomain::Face);
344 cap_material_indices.materialize(
345 result_material_indices.
span.slice(cap_faces_index, cap_nfaces));
346 result_material_indices.
finish();
350 index_orig =
static_cast<int *
>(
356 index_orig =
static_cast<int *
>(
362 index_orig =
static_cast<int *
>(
368 index_orig =
static_cast<int *
>(
380 if (mesh->verts_num == 0) {
383 if (start_cap_ob && start_cap_ob != ctx->
object) {
385 if (start_cap_mesh) {
395 float length = amd->
length;
399 bool offset_has_scale;
400 float current_offset[4][4];
401 float final_offset[4][4];
402 int *full_doubles_map =
nullptr;
409 int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_nfaces = 0, start_cap_nloops = 0;
410 int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_nfaces = 0, end_cap_nloops = 0;
411 int result_nverts = 0, result_nedges = 0, result_nfaces = 0, result_nloops = 0;
412 int chunk_nverts, chunk_nedges, chunk_nloops, chunk_nfaces;
413 int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts;
415 Mesh *
result, *start_cap_mesh =
nullptr, *end_cap_mesh =
nullptr;
417 int *vgroup_start_cap_remap =
nullptr;
418 int vgroup_start_cap_remap_len = 0;
419 int *vgroup_end_cap_remap =
nullptr;
420 int vgroup_end_cap_remap_len = 0;
423 chunk_nedges = mesh->edges_num;
424 chunk_nloops = mesh->corners_num;
425 chunk_nfaces = mesh->faces_num;
430 if (start_cap_ob && start_cap_ob != ctx->
object) {
433 start_cap_ob, ctx->
object, &vgroup_start_cap_remap_len);
437 if (start_cap_mesh) {
439 start_cap_nverts = start_cap_mesh->
verts_num;
440 start_cap_nedges = start_cap_mesh->
edges_num;
442 start_cap_nfaces = start_cap_mesh->
faces_num;
446 if (end_cap_ob && end_cap_ob != ctx->
object) {
449 end_cap_ob, ctx->
object, &vgroup_end_cap_remap_len);
455 end_cap_nverts = end_cap_mesh->verts_num;
456 end_cap_nedges = end_cap_mesh->edges_num;
457 end_cap_nloops = end_cap_mesh->corners_num;
458 end_cap_nfaces = end_cap_mesh->faces_num;
473 offset[3][j] += amd->
scale[j] * (bounds.
max[j] - bounds.
min[j]);
479 float result_mat[4][4];
500 float scale_fac =
mat4_to_scale(curve_ob->object_to_world().ptr());
506 const size_t max_verts_num = 1 << 26;
511 const float float_epsilon = 1e-6f;
512 bool offset_is_too_small =
false;
513 float dist =
len_v3(offset[3]);
515 if (dist > float_epsilon) {
518 count = (length + float_epsilon) / dist + 1;
523 if ((
size_t(
count) *
size_t(chunk_nverts) +
size_t(start_cap_nverts) +
524 size_t(end_cap_nverts)) > max_verts_num)
527 offset_is_too_small =
true;
533 offset_is_too_small =
true;
536 if (offset_is_too_small) {
540 "The offset is too small, we cannot generate the amount of geometry it would require");
546 else if ((
size_t(
count) *
size_t(chunk_nverts) +
size_t(start_cap_nverts) +
547 size_t(end_cap_nverts)) > max_verts_num)
552 "The amount of copies is too high, we cannot generate the amount of "
553 "geometry it would require");
561 result_nverts = chunk_nverts *
count + start_cap_nverts + end_cap_nverts;
562 result_nedges = chunk_nedges *
count + start_cap_nedges + end_cap_nedges;
563 result_nloops = chunk_nloops *
count + start_cap_nloops + end_cap_nloops;
564 result_nfaces = chunk_nfaces *
count + start_cap_nfaces + end_cap_nfaces;
568 mesh, result_nverts, result_nedges, result_nfaces, result_nloops);
577 full_doubles_map =
static_cast<int *
>(
MEM_malloc_arrayN(result_nverts,
sizeof(
int), __func__));
578 copy_vn_i(full_doubles_map, result_nverts, -1);
587 result_face_offsets.
take_front(mesh->faces_num).
copy_from(mesh->face_offsets().drop_back(1));
590 first_chunk_start = 0;
591 first_chunk_nverts = chunk_nverts;
596 if (!use_recalc_normals) {
597 src_vert_normals = mesh->vert_normals();
600 .take_front(src_vert_normals.
size())
601 .copy_from(src_vert_normals);
604 for (c = 1; c <
count; c++) {
609 &mesh->corner_data, &result->corner_data, 0, c * chunk_nloops, chunk_nloops);
612 const int vert_offset = c * chunk_nverts;
615 mul_m4_m4m4(current_offset, current_offset, offset);
618 for (i = 0; i < chunk_nverts; i++) {
619 const int i_dst = vert_offset + i;
620 mul_m4_v3(current_offset, result_positions[i_dst]);
624 copy_v3_v3(dst_vert_normals[i_dst], src_vert_normals[i]);
631 edge = &result_edges[c * chunk_nedges];
632 for (i = 0; i < chunk_nedges; i++, edge++) {
633 (*edge) += c * chunk_nverts;
636 for (i = 0; i < chunk_nfaces; i++) {
637 result_face_offsets[c * chunk_nfaces + i] = result_face_offsets[i] + c * chunk_nloops;
641 const int chunk_corner_start = c * chunk_nloops;
642 for (i = 0; i < chunk_nloops; i++) {
643 result_corner_verts[chunk_corner_start + i] += c * chunk_nverts;
644 result_corner_edges[chunk_corner_start + i] += c * chunk_nedges;
648 if (use_merge && (c >= 1)) {
649 if (!offset_has_scale && (c >= 2)) {
653 int this_chunk_index = c * chunk_nverts;
654 int prev_chunk_index = (c - 1) * chunk_nverts;
655 for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) {
656 int target = full_doubles_map[prev_chunk_index];
658 target += chunk_nverts;
659 while (target != -1 && !
ELEM(full_doubles_map[target], -1, target)) {
663 result_positions[full_doubles_map[target]],
666 target = full_doubles_map[target];
673 full_doubles_map[this_chunk_index] = target;
679 (c - 1) * chunk_nverts,
691 for (i = 0; i < totuv; i++) {
694 dmloopuv += chunk_nloops;
695 for (c = 1; c <
count; c++) {
696 const float uv_offset[2] = {
700 int l_index = chunk_nloops;
701 for (; l_index-- != 0; dmloopuv++) {
702 (*dmloopuv)[0] += uv_offset[0];
703 (*dmloopuv)[1] += uv_offset[1];
709 if (!use_merge && !mesh->runtime->subsurf_optimal_display_edges.is_empty()) {
710 const BoundedBitSpan src = mesh->runtime->subsurf_optimal_display_edges;
712 result->runtime->subsurf_optimal_display_edges.resize(result->edges_num);
715 dst.
slice({i * mesh->edges_num, mesh->edges_num}).copy_from(src);
718 if (start_cap_mesh) {
720 {result_nedges - start_cap_nedges - end_cap_nedges, start_cap_mesh->
edges_num});
721 if (start_cap_mesh->
runtime->subsurf_optimal_display_edges.is_empty()) {
730 {result_nedges - end_cap_nedges, end_cap_mesh->edges_num});
731 if (end_cap_mesh->runtime->subsurf_optimal_display_edges.is_empty()) {
735 cap_bits.
copy_from(end_cap_mesh->runtime->subsurf_optimal_display_edges);
740 last_chunk_start = (
count - 1) * chunk_nverts;
741 last_chunk_nverts = chunk_nverts;
757 if (start_cap_mesh) {
758 float start_offset[4][4];
759 int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts;
764 result_nverts - start_cap_nverts - end_cap_nverts,
765 result_nedges - start_cap_nedges - end_cap_nedges,
766 result_nloops - start_cap_nloops - end_cap_nloops,
767 result_nfaces - start_cap_nfaces - end_cap_nfaces,
772 vgroup_start_cap_remap,
773 vgroup_start_cap_remap_len,
788 float end_offset[4][4];
789 int end_cap_start = result_nverts - end_cap_nverts;
794 result_nverts - end_cap_nverts,
795 result_nedges - end_cap_nedges,
796 result_nloops - end_cap_nloops,
797 result_nfaces - end_cap_nfaces,
802 vgroup_end_cap_remap,
803 vgroup_end_cap_remap_len,
825 for (i = 0; i < result_nverts; i++) {
826 int new_i = full_doubles_map[i];
831 while (!
ELEM(full_doubles_map[new_i], -1, new_i)) {
832 new_i = full_doubles_map[new_i];
835 full_doubles_map[i] = -1;
838 full_doubles_map[i] = new_i;
843 if (tot_doubles > 0) {
845 result = geometry::mesh_merge_verts(
846 *tmp,
MutableSpan<int>{full_doubles_map, result->verts_num}, tot_doubles,
false);
852 if (vgroup_start_cap_remap) {
855 if (vgroup_end_cap_remap) {