154 const int target_start,
155 const int target_verts_num,
156 const int source_start,
157 const int source_verts_num,
161 int i_source, i_target, i_target_low_bound, target_end, source_end;
162 SortVertsElem *sve_source, *sve_target, *sve_target_low_bound;
163 bool target_scan_completed;
165 target_end = target_start + target_verts_num;
166 source_end = source_start + source_verts_num;
175 svert_from_mvert(sorted_verts_target, vert_positions, target_start, target_end);
178 svert_from_mvert(sorted_verts_source, vert_positions, source_start, source_end);
184 sve_target_low_bound = sorted_verts_target;
185 i_target_low_bound = 0;
186 target_scan_completed =
false;
190 for (i_source = 0, sve_source = sorted_verts_source; i_source < source_verts_num;
191 i_source++, sve_source++)
193 int best_target_vertex = -1;
194 float best_dist_sq = dist * dist;
195 float sve_source_sumco;
198 if (doubles_map[sve_source->
vertex_num] != -1) {
203 if (target_scan_completed) {
208 sve_source_sumco =
sum_v3(sve_source->
co);
212 while ((i_target_low_bound < target_verts_num) &&
213 (sve_target_low_bound->
sum_co < sve_source_sumco - dist3))
215 i_target_low_bound++;
216 sve_target_low_bound++;
219 if (i_target_low_bound >= target_verts_num) {
221 target_scan_completed =
true;
226 i_target = i_target_low_bound;
227 sve_target = sve_target_low_bound;
232 while ((i_target < target_verts_num) && (sve_target->
sum_co <= sve_source_sumco + dist3)) {
236 if (dist_sq <= best_dist_sq) {
238 best_dist_sq = dist_sq;
246 while (best_target_vertex != -1 &&
247 !
ELEM(doubles_map[best_target_vertex], -1, best_target_vertex))
250 vert_positions[doubles_map[best_target_vertex]],
253 best_target_vertex = doubles_map[best_target_vertex];
256 best_target_vertex = -1;
264 doubles_map[sve_source->
vertex_num] = best_target_vertex;
273 const float cap_offset[4][4],
274 uint cap_verts_index,
275 uint cap_edges_index,
303 for (
i = 0;
i < cap_nverts;
i++) {
304 mul_m4_v3(cap_offset, result_positions[cap_verts_index +
i]);
309 for (
i = 0;
i < cap_nverts;
i++) {
316 if (!
result->deform_verts().is_empty()) {
322 edge = &result_edges[cap_edges_index];
323 for (
i = 0;
i < cap_nedges;
i++, edge++) {
324 (*edge) += cap_verts_index;
328 for (
i = 0;
i < cap_nfaces;
i++) {
329 result_face_offsets[cap_faces_index +
i] = cap_face_offsets[
i] + cap_loops_index;
333 for (
i = 0;
i < cap_nloops;
i++) {
334 result_corner_verts[cap_loops_index +
i] += cap_verts_index;
335 result_corner_edges[cap_loops_index +
i] += cap_edges_index;
339 if (
const VArray cap_material_indices = *cap_attributes.
lookup<
int>(
"material_index",
346 cap_material_indices.materialize(
347 result_material_indices.
span.slice(cap_faces_index, cap_nfaces));
348 result_material_indices.
finish();
352 index_orig =
static_cast<int *
>(
358 index_orig =
static_cast<int *
>(
364 index_orig =
static_cast<int *
>(
370 index_orig =
static_cast<int *
>(
394 bool offset_has_scale;
395 float current_offset[4][4];
396 float final_offset[4][4];
397 int *full_doubles_map =
nullptr;
404 int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_nfaces = 0, start_cap_nloops = 0;
405 int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_nfaces = 0, end_cap_nloops = 0;
406 int result_nverts = 0, result_nedges = 0, result_nfaces = 0, result_nloops = 0;
407 int chunk_nverts, chunk_nedges, chunk_nloops, chunk_nfaces;
408 int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts;
410 Mesh *
result, *start_cap_mesh =
nullptr, *end_cap_mesh =
nullptr;
412 int *vgroup_start_cap_remap =
nullptr;
413 int vgroup_start_cap_remap_len = 0;
414 int *vgroup_end_cap_remap =
nullptr;
415 int vgroup_end_cap_remap_len = 0;
425 if (start_cap_ob && start_cap_ob != ctx->
object) {
428 start_cap_ob, ctx->
object, &vgroup_start_cap_remap_len);
432 if (start_cap_mesh) {
434 start_cap_nverts = start_cap_mesh->
verts_num;
435 start_cap_nedges = start_cap_mesh->
edges_num;
437 start_cap_nfaces = start_cap_mesh->
faces_num;
441 if (end_cap_ob && end_cap_ob != ctx->
object) {
444 end_cap_ob, ctx->
object, &vgroup_end_cap_remap_len);
450 end_cap_nverts = end_cap_mesh->verts_num;
451 end_cap_nedges = end_cap_mesh->edges_num;
452 end_cap_nloops = end_cap_mesh->corners_num;
453 end_cap_nfaces = end_cap_mesh->faces_num;
474 float result_mat[4][4];
495 float scale_fac =
mat4_to_scale(curve_ob->object_to_world().ptr());
501 const size_t max_verts_num = 1 << 26;
506 const float float_epsilon = 1e-6f;
507 bool offset_is_too_small =
false;
508 float dist =
len_v3(offset[3]);
510 if (dist > float_epsilon) {
518 if ((
size_t(
count) *
size_t(chunk_nverts) +
size_t(start_cap_nverts) +
519 size_t(end_cap_nverts)) > max_verts_num)
522 offset_is_too_small =
true;
528 offset_is_too_small =
true;
531 if (offset_is_too_small) {
535 "The offset is too small, we cannot generate the amount of geometry it would require");
541 else if ((
size_t(
count) *
size_t(chunk_nverts) +
size_t(start_cap_nverts) +
542 size_t(end_cap_nverts)) > max_verts_num)
547 "The amount of copies is too high, we cannot generate the amount of "
548 "geometry it would require");
554 result_nverts = chunk_nverts *
count + start_cap_nverts + end_cap_nverts;
555 result_nedges = chunk_nedges *
count + start_cap_nedges + end_cap_nedges;
556 result_nloops = chunk_nloops *
count + start_cap_nloops + end_cap_nloops;
557 result_nfaces = chunk_nfaces *
count + start_cap_nfaces + end_cap_nfaces;
561 mesh, result_nverts, result_nedges, result_nfaces, result_nloops);
571 copy_vn_i(full_doubles_map, result_nverts, -1);
583 first_chunk_start = 0;
584 first_chunk_nverts = chunk_nverts;
589 if (!use_recalc_normals) {
590 src_vert_normals = mesh->vert_normals();
593 .take_front(src_vert_normals.
size())
594 .copy_from(src_vert_normals);
597 for (c = 1; c <
count; c++) {
606 mul_m4_m4m4(current_offset, current_offset, offset);
610 const int vert_offset = c * chunk_nverts;
611 for (
i = 0;
i < chunk_nverts;
i++) {
612 const int i_dst = vert_offset +
i;
613 mul_m4_v3(current_offset, result_positions[i_dst]);
617 copy_v3_v3(dst_vert_normals[i_dst], src_vert_normals[
i]);
626 edge = &result_edges[c * chunk_nedges];
627 for (
i = 0;
i < chunk_nedges;
i++, edge++) {
628 (*edge) += c * chunk_nverts;
633 for (
i = 0;
i < chunk_nfaces;
i++) {
634 result_face_offsets[c * chunk_nfaces +
i] = result_face_offsets[
i] + c * chunk_nloops;
640 const int chunk_corner_start = c * chunk_nloops;
641 for (
i = 0;
i < chunk_nloops;
i++) {
642 result_corner_verts[chunk_corner_start +
i] += c * chunk_nverts;
643 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 uv_map += 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; uv_map++) {
702 (*uv_map)[0] += uv_offset[0];
703 (*uv_map)[1] += uv_offset[1];
709 if (!use_merge && !mesh->
runtime->subsurf_optimal_display_edges.is_empty()) {
712 result->runtime->subsurf_optimal_display_edges.resize(
result->edges_num);
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) {
852 if (vgroup_start_cap_remap) {
855 if (vgroup_end_cap_remap) {