Blender V4.3
MOD_solidify_nonmanifold.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_math_matrix.h"
10#include "BLI_math_vector.h"
11#include "BLI_utildefines.h"
12
13#include "DNA_mesh_types.h"
14#include "DNA_meshdata_types.h"
15#include "DNA_object_types.h"
16
17#include "MEM_guardedalloc.h"
18
19#include "BKE_attribute.hh"
20#include "BKE_customdata.hh"
21#include "BKE_deform.hh"
22#include "BKE_mesh.hh"
23
24#include "MOD_modifiertypes.hh"
25#include "MOD_solidify_util.hh" /* Own include. */
26#include "MOD_util.hh"
27
28/* -------------------------------------------------------------------- */
35static float project_v3_v3(float r[3], const float a[3])
36{
37 float d = dot_v3v3(r, a);
38 r[0] -= a[0] * d;
39 r[1] -= a[1] * d;
40 r[2] -= a[2] * d;
41 return d;
42}
43
44static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3],
45 const float ref_n[3],
46 const float axis[3])
47{
48 float d = dot_v3v3(n, ref_n);
49 CLAMP(d, -1, 1);
50 float angle = acosf(d);
51 float cross[3];
52 cross_v3_v3v3(cross, n, ref_n);
53 if (dot_v3v3(cross, axis) >= 0) {
54 angle = 2 * M_PI - angle;
55 }
56 return angle;
57}
58
59static float clamp_nonzero(const float value, const float epsilon)
60{
61 BLI_assert(!(epsilon < 0.0f));
62 /* Return closest value with `abs(value) >= epsilon`. */
63 if (value < 0.0f) {
64 return min_ff(value, -epsilon);
65 }
66 return max_ff(value, epsilon);
67}
68
71/* -------------------------------------------------------------------- */
75/* Data structures for manifold solidify. */
76
77struct NewEdgeRef;
78
85
92
97
105
120
122 float angle;
124};
125
126static int comp_float_int_pair(const void *a, const void *b)
127{
128 FaceKeyPair *x = (FaceKeyPair *)a;
129 FaceKeyPair *y = (FaceKeyPair *)b;
130 return int(x->angle > y->angle) - int(x->angle < y->angle);
131}
132
133/* NOLINTNEXTLINE: readability-function-size */
135 const ModifierEvalContext *ctx,
136 Mesh *mesh)
137{
138 using namespace blender;
139 Mesh *result;
141
142 const uint verts_num = uint(mesh->verts_num);
143 const uint edges_num = uint(mesh->edges_num);
144 const uint faces_num = uint(mesh->faces_num);
145
146 if (faces_num == 0 && verts_num != 0) {
147 return mesh;
148 }
149
150 /* Only use material offsets if we have 2 or more materials. */
151 const short mat_nrs = ctx->object->totcol > 1 ? ctx->object->totcol : 1;
152 const short mat_nr_max = mat_nrs - 1;
153 const short mat_ofs = mat_nrs > 1 ? smd->mat_ofs : 0;
154 const short mat_ofs_rim = mat_nrs > 1 ? smd->mat_ofs_rim : 0;
155
156 /* #ofs_front and #ofs_back are the offset from the original
157 * surface along the normal, where #oft_front is along the positive
158 * and #oft_back is along the negative normal. */
159 const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset;
160 const float ofs_back = ofs_front - smd->offset * smd->offset_fac;
161 /* #ofs_front_clamped and #ofs_back_clamped are the same as
162 * #ofs_front and #ofs_back, but never zero. */
163 const float ofs_front_clamped = clamp_nonzero(ofs_front, 1e-5f);
164 const float ofs_back_clamped = clamp_nonzero(ofs_back, 1e-5f);
165 const float offset_fac_vg = smd->offset_fac_vg;
166 const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
167 const float offset = fabsf(smd->offset) * smd->offset_clamp;
168 const bool do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP;
169 /* #do_flip, flips the normals of the result. This is inverted if negative thickness
170 * is used, since simple solidify with negative thickness keeps the faces facing outside. */
171 const bool do_flip = ((smd->flag & MOD_SOLIDIFY_FLIP) != 0) == (smd->offset > 0);
172 const bool do_rim = smd->flag & MOD_SOLIDIFY_RIM;
173 const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) ==
174 0;
175 const bool do_clamp = (smd->offset_clamp != 0.0f);
176
177 const float bevel_convex = smd->bevel_convex;
178
179 const MDeformVert *dvert;
180 const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
181 int defgrp_index;
182 const int shell_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->shell_defgrp_name);
183 const int rim_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->rim_defgrp_name);
184
185 MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
186
187 const bool do_flat_faces = dvert && (smd->flag & MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES);
188
189 const blender::Span<blender::float3> orig_vert_positions = mesh->vert_positions();
190 const blender::Span<int2> orig_edges = mesh->edges();
191 const blender::OffsetIndices orig_faces = mesh->faces();
192 const blender::Span<int> orig_corner_verts = mesh->corner_verts();
193 const blender::Span<int> orig_corner_edges = mesh->corner_edges();
194
195 /* These might be null. */
196 const float *orig_vert_bweight = static_cast<const float *>(
197 CustomData_get_layer_named(&mesh->vert_data, CD_PROP_FLOAT, "bevel_weight_vert"));
198 const float *orig_edge_bweight = static_cast<const float *>(
199 CustomData_get_layer_named(&mesh->edge_data, CD_PROP_FLOAT, "bevel_weight_edge"));
200 const float *orig_edge_crease = static_cast<const float *>(
201 CustomData_get_layer_named(&mesh->edge_data, CD_PROP_FLOAT, "crease_edge"));
202
203 uint new_verts_num = 0;
204 uint new_edges_num = 0;
205 uint new_loops_num = 0;
206 uint new_faces_num = 0;
207
208#define MOD_SOLIDIFY_EMPTY_TAG uint(-1)
209
210 /* Calculate only face normals. Copied because they are modified directly below. */
211 blender::Array<blender::float3> face_nors = mesh->face_normals();
212
213 NewFaceRef *face_sides_arr = static_cast<NewFaceRef *>(
214 MEM_malloc_arrayN(faces_num * 2, sizeof(*face_sides_arr), __func__));
215 bool *null_faces =
217 static_cast<bool *>(MEM_calloc_arrayN(faces_num, sizeof(*null_faces), __func__)) :
218 nullptr;
219 uint largest_ngon = 3;
220 /* Calculate face to #NewFaceRef map. */
221 {
222 for (const int i : orig_faces.index_range()) {
223 const blender::IndexRange &face = orig_faces[i];
224 /* Make normals for faces without area (should really be avoided though). */
225 if (len_squared_v3(face_nors[i]) < 0.5f) {
226 const int2 &edge = orig_edges[orig_corner_edges[face.start()]];
227 float edgedir[3];
228 sub_v3_v3v3(edgedir, orig_vert_positions[edge[1]], orig_vert_positions[edge[0]]);
229 if (fabsf(edgedir[2]) < fabsf(edgedir[1])) {
230 face_nors[i][2] = 1.0f;
231 }
232 else {
233 face_nors[i][1] = 1.0f;
234 }
235 if (null_faces) {
236 null_faces[i] = true;
237 }
238 }
239
240 NewEdgeRef **link_edges = static_cast<NewEdgeRef **>(
241 MEM_calloc_arrayN(uint(face.size()), sizeof(*link_edges), __func__));
242
243 NewFaceRef new_face_ref_a{};
244 new_face_ref_a.face = face;
245 new_face_ref_a.index = uint(i);
246 new_face_ref_a.reversed = false;
247 new_face_ref_a.link_edges = link_edges;
248 face_sides_arr[i * 2] = new_face_ref_a;
249
250 link_edges = static_cast<NewEdgeRef **>(
251 MEM_calloc_arrayN(uint(face.size()), sizeof(*link_edges), __func__));
252
253 NewFaceRef new_face_ref_b{};
254 new_face_ref_b.face = face;
255 new_face_ref_b.index = uint(i);
256 new_face_ref_b.reversed = true;
257 new_face_ref_b.link_edges = link_edges;
258 face_sides_arr[i * 2 + 1] = new_face_ref_b;
259
260 if (face.size() > largest_ngon) {
261 largest_ngon = uint(face.size());
262 }
263 /* add to final mesh face count */
264 if (do_shell) {
265 new_faces_num += 2;
266 new_loops_num += uint(face.size() * 2);
267 }
268 }
269 }
270
271 uint *edge_adj_faces_len = static_cast<uint *>(
272 MEM_calloc_arrayN(edges_num, sizeof(*edge_adj_faces_len), __func__));
273 /* Count for each edge how many faces it has adjacent. */
274 {
275 for (const int64_t i : orig_faces.index_range()) {
276 for (const int64_t edge : orig_corner_edges.slice(orig_faces[i])) {
277 edge_adj_faces_len[edge]++;
278 }
279 }
280 }
281
282 /* Original edge to #NewEdgeRef map. */
283 NewEdgeRef ***orig_edge_data_arr = static_cast<NewEdgeRef ***>(
284 MEM_calloc_arrayN(edges_num, sizeof(*orig_edge_data_arr), __func__));
285 /* Original edge length cache. */
286 float *orig_edge_lengths = static_cast<float *>(
287 MEM_calloc_arrayN(edges_num, sizeof(*orig_edge_lengths), __func__));
288 /* Edge groups for every original vert. */
289 EdgeGroup **orig_vert_groups_arr = static_cast<EdgeGroup **>(
290 MEM_calloc_arrayN(verts_num, sizeof(*orig_vert_groups_arr), __func__));
291 /* vertex map used to map duplicates. */
292 uint *vm = static_cast<uint *>(MEM_malloc_arrayN(verts_num, sizeof(*vm), __func__));
293 for (uint i = 0; i < verts_num; i++) {
294 vm[i] = i;
295 }
296
297 uint edge_index = 0;
298 uint loop_index = 0;
299 uint face_index = 0;
300
301 bool has_singularities = false;
302
303 /* Vert edge adjacent map. */
304 OldVertEdgeRef **vert_adj_edges = static_cast<OldVertEdgeRef **>(
305 MEM_calloc_arrayN(verts_num, sizeof(*vert_adj_edges), __func__));
306 /* Original vertex positions (changed for degenerated geometry). */
307 float(*orig_mvert_co)[3] = static_cast<float(*)[3]>(
308 MEM_malloc_arrayN(verts_num, sizeof(*orig_mvert_co), __func__));
309 /* Fill in the original vertex positions. */
310 for (uint i = 0; i < verts_num; i++) {
311 orig_mvert_co[i][0] = orig_vert_positions[i][0];
312 orig_mvert_co[i][1] = orig_vert_positions[i][1];
313 orig_mvert_co[i][2] = orig_vert_positions[i][2];
314 }
315
316 /* Create edge to #NewEdgeRef map. */
317 {
318 OldEdgeFaceRef **edge_adj_faces = static_cast<OldEdgeFaceRef **>(
319 MEM_calloc_arrayN(edges_num, sizeof(*edge_adj_faces), __func__));
320
321 /* Create link_faces for edges. */
322 {
323 for (const int64_t i : orig_faces.index_range()) {
324 for (const int64_t corner : orig_faces[i]) {
325 const int vert = orig_corner_verts[corner];
326 const int edge = orig_corner_edges[corner];
327 const bool reversed = orig_edges[edge][1] != vert;
328 OldEdgeFaceRef *old_face_edge_ref = edge_adj_faces[edge];
329 if (old_face_edge_ref == nullptr) {
330 const uint len = edge_adj_faces_len[edge];
331 BLI_assert(len > 0);
332 uint *adj_faces = static_cast<uint *>(
333 MEM_malloc_arrayN(len, sizeof(*adj_faces), __func__));
334 bool *adj_faces_reversed = static_cast<bool *>(
335 MEM_malloc_arrayN(len, sizeof(*adj_faces_reversed), __func__));
336 adj_faces[0] = uint(i);
337 for (uint k = 1; k < len; k++) {
338 adj_faces[k] = MOD_SOLIDIFY_EMPTY_TAG;
339 }
340 adj_faces_reversed[0] = reversed;
341 OldEdgeFaceRef *ref = static_cast<OldEdgeFaceRef *>(
342 MEM_mallocN(sizeof(*ref), __func__));
343 *ref = OldEdgeFaceRef{adj_faces, len, adj_faces_reversed, 1};
344 edge_adj_faces[edge] = ref;
345 }
346 else {
347 for (uint k = 1; k < old_face_edge_ref->faces_len; k++) {
348 if (old_face_edge_ref->faces[k] == MOD_SOLIDIFY_EMPTY_TAG) {
349 old_face_edge_ref->faces[k] = uint(i);
350 old_face_edge_ref->faces_reversed[k] = reversed;
351 break;
352 }
353 }
354 }
355 }
356 }
357 }
358
359 float edgedir[3] = {0, 0, 0};
360 uint *vert_adj_edges_len = static_cast<uint *>(
361 MEM_calloc_arrayN(verts_num, sizeof(*vert_adj_edges_len), __func__));
362
363 /* Calculate edge lengths and len vert_adj edges. */
364 {
365 bool *face_singularity = static_cast<bool *>(
366 MEM_calloc_arrayN(faces_num, sizeof(*face_singularity), __func__));
367
368 const float merge_tolerance_sqr = smd->merge_tolerance * smd->merge_tolerance;
369 uint *combined_verts = static_cast<uint *>(
370 MEM_calloc_arrayN(verts_num, sizeof(*combined_verts), __func__));
371
372 for (uint i = 0; i < edges_num; i++) {
373 const int2 &edge = orig_edges[i];
374 if (edge_adj_faces_len[i] > 0) {
375 uint v1 = vm[edge[0]];
376 uint v2 = vm[edge[1]];
377 if (v1 == v2) {
378 continue;
379 }
380
381 if (v2 < v1) {
382 std::swap(v1, v2);
383 }
384 sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
385 orig_edge_lengths[i] = len_squared_v3(edgedir);
386
387 if (orig_edge_lengths[i] <= merge_tolerance_sqr) {
388 /* Merge verts. But first check if that would create a higher face count. */
389 /* This check is very slow. It would need the vertex edge links to get
390 * accelerated that are not yet available at this point. */
391 bool can_merge = true;
392 for (uint k = 0; k < edges_num && can_merge; k++) {
393 if (k != i && edge_adj_faces_len[k] > 0 &&
394 (ELEM(vm[orig_edges[k][0]], v1, v2) != ELEM(vm[orig_edges[k][1]], v1, v2)))
395 {
396 for (uint j = 0; j < edge_adj_faces[k]->faces_len && can_merge; j++) {
397 const blender::IndexRange face = orig_faces[edge_adj_faces[k]->faces[j]];
398 uint changes = 0;
399 int cur = face.size() - 1;
400 for (int next = 0; next < face.size() && changes <= 2; next++) {
401 uint cur_v = vm[orig_corner_verts[face[cur]]];
402 uint next_v = vm[orig_corner_verts[face[next]]];
403 changes += (ELEM(cur_v, v1, v2) != ELEM(next_v, v1, v2));
404 cur = next;
405 }
406 can_merge = can_merge && changes <= 2;
407 }
408 }
409 }
410
411 if (!can_merge) {
412 orig_edge_lengths[i] = 0.0f;
413 vert_adj_edges_len[v1]++;
414 vert_adj_edges_len[v2]++;
415 continue;
416 }
417
418 mul_v3_fl(edgedir,
419 (combined_verts[v2] + 1) /
420 float(combined_verts[v1] + combined_verts[v2] + 2));
421 add_v3_v3(orig_mvert_co[v1], edgedir);
422 for (uint j = v2; j < verts_num; j++) {
423 if (vm[j] == v2) {
424 vm[j] = v1;
425 }
426 }
427 vert_adj_edges_len[v1] += vert_adj_edges_len[v2];
428 vert_adj_edges_len[v2] = 0;
429 combined_verts[v1] += combined_verts[v2] + 1;
430
431 if (do_shell) {
432 new_loops_num -= edge_adj_faces_len[i] * 2;
433 }
434
435 edge_adj_faces_len[i] = 0;
436 MEM_freeN(edge_adj_faces[i]->faces);
437 MEM_freeN(edge_adj_faces[i]->faces_reversed);
438 MEM_freeN(edge_adj_faces[i]);
439 edge_adj_faces[i] = nullptr;
440 }
441 else {
442 orig_edge_lengths[i] = sqrtf(orig_edge_lengths[i]);
443 vert_adj_edges_len[v1]++;
444 vert_adj_edges_len[v2]++;
445 }
446 }
447 }
448 /* remove zero faces in a second pass */
449 for (uint i = 0; i < edges_num; i++) {
450 const int2 &edge = orig_edges[i];
451 const uint v1 = vm[edge[0]];
452 const uint v2 = vm[edge[1]];
453 if (v1 == v2 && edge_adj_faces[i]) {
454 /* Remove faces. */
455 for (uint j = 0; j < edge_adj_faces[i]->faces_len; j++) {
456 const uint face = edge_adj_faces[i]->faces[j];
457 if (!face_singularity[face]) {
458 bool is_singularity = true;
459 for (const int vert : orig_corner_verts.slice(orig_faces[face])) {
460 if (vm[vert] != v1) {
461 is_singularity = false;
462 break;
463 }
464 }
465 if (is_singularity) {
466 face_singularity[face] = true;
467 /* remove from final mesh face count */
468 if (do_shell) {
469 new_faces_num -= 2;
470 }
471 }
472 }
473 }
474
475 if (do_shell) {
476 new_loops_num -= edge_adj_faces_len[i] * 2;
477 }
478
479 edge_adj_faces_len[i] = 0;
480 MEM_freeN(edge_adj_faces[i]->faces);
481 MEM_freeN(edge_adj_faces[i]->faces_reversed);
482 MEM_freeN(edge_adj_faces[i]);
483 edge_adj_faces[i] = nullptr;
484 }
485 }
486
487 MEM_freeN(face_singularity);
488 MEM_freeN(combined_verts);
489 }
490
491 /* Create vert_adj_edges for verts. */
492 {
493 for (uint i = 0; i < edges_num; i++) {
494 const int2 &edge = orig_edges[i];
495 if (edge_adj_faces_len[i] > 0) {
496 const int vs[2] = {int(vm[edge[0]]), int(vm[edge[1]])};
497 uint invalid_edge_index = 0;
498 bool invalid_edge_reversed = false;
499 for (uint j = 0; j < 2; j++) {
500 const int vert = vs[j];
501 const uint len = vert_adj_edges_len[vert];
502 if (len > 0) {
503 OldVertEdgeRef *old_edge_vert_ref = vert_adj_edges[vert];
504 if (old_edge_vert_ref == nullptr) {
505 uint *adj_edges = static_cast<uint *>(
506 MEM_calloc_arrayN(len, sizeof(*adj_edges), __func__));
507 adj_edges[0] = i;
508 for (uint k = 1; k < len; k++) {
509 adj_edges[k] = MOD_SOLIDIFY_EMPTY_TAG;
510 }
511 OldVertEdgeRef *ref = static_cast<OldVertEdgeRef *>(
512 MEM_mallocN(sizeof(*ref), __func__));
513 *ref = OldVertEdgeRef{adj_edges, 1};
514 vert_adj_edges[vert] = ref;
515 }
516 else {
517 const uint *f = old_edge_vert_ref->edges;
518 for (uint k = 0; k < len && k <= old_edge_vert_ref->edges_len; k++, f++) {
519 const uint edge = old_edge_vert_ref->edges[k];
520 if (edge == MOD_SOLIDIFY_EMPTY_TAG || k == old_edge_vert_ref->edges_len) {
521 old_edge_vert_ref->edges[k] = i;
522 old_edge_vert_ref->edges_len++;
523 break;
524 }
525 if (vm[orig_edges[edge][0]] == vs[1 - j]) {
526 invalid_edge_index = edge + 1;
527 invalid_edge_reversed = (j == 0);
528 break;
529 }
530 if (vm[orig_edges[edge][1]] == vs[1 - j]) {
531 invalid_edge_index = edge + 1;
532 invalid_edge_reversed = (j == 1);
533 break;
534 }
535 }
536 if (invalid_edge_index) {
537 if (j == 1) {
538 /* Should never actually be executed. */
539 vert_adj_edges[vs[0]]->edges_len--;
540 }
541 break;
542 }
543 }
544 }
545 }
546 /* Remove zero faces that are in shape of an edge. */
547 if (invalid_edge_index) {
548 const uint tmp = invalid_edge_index - 1;
549 invalid_edge_index = i;
550 i = tmp;
551 OldEdgeFaceRef *i_adj_faces = edge_adj_faces[i];
552 OldEdgeFaceRef *invalid_adj_faces = edge_adj_faces[invalid_edge_index];
553 uint j = 0;
554 for (uint k = 0; k < i_adj_faces->faces_len; k++) {
555 for (uint l = 0; l < invalid_adj_faces->faces_len; l++) {
556 if (i_adj_faces->faces[k] == invalid_adj_faces->faces[l] &&
557 i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG)
558 {
559 i_adj_faces->faces[k] = MOD_SOLIDIFY_EMPTY_TAG;
560 invalid_adj_faces->faces[l] = MOD_SOLIDIFY_EMPTY_TAG;
561 j++;
562 }
563 }
564 }
565 /* remove from final face count */
566 if (do_shell) {
567 new_faces_num -= 2 * j;
568 new_loops_num -= 4 * j;
569 }
570 const uint len = i_adj_faces->faces_len + invalid_adj_faces->faces_len - 2 * j;
571 uint *adj_faces = static_cast<uint *>(
572 MEM_malloc_arrayN(len, sizeof(*adj_faces), __func__));
573 bool *adj_faces_loops_reversed = static_cast<bool *>(
574 MEM_malloc_arrayN(len, sizeof(*adj_faces_loops_reversed), __func__));
575 /* Clean merge of adj_faces. */
576 j = 0;
577 for (uint k = 0; k < i_adj_faces->faces_len; k++) {
578 if (i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) {
579 adj_faces[j] = i_adj_faces->faces[k];
580 adj_faces_loops_reversed[j++] = i_adj_faces->faces_reversed[k];
581 }
582 }
583 for (uint k = 0; k < invalid_adj_faces->faces_len; k++) {
584 if (invalid_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) {
585 adj_faces[j] = invalid_adj_faces->faces[k];
586 adj_faces_loops_reversed[j++] = (invalid_edge_reversed !=
587 invalid_adj_faces->faces_reversed[k]);
588 }
589 }
590 BLI_assert(j == len);
591 edge_adj_faces_len[invalid_edge_index] = 0;
592 edge_adj_faces_len[i] = len;
593 MEM_freeN(i_adj_faces->faces);
594 MEM_freeN(i_adj_faces->faces_reversed);
595 i_adj_faces->faces_len = len;
596 i_adj_faces->faces = adj_faces;
597 i_adj_faces->faces_reversed = adj_faces_loops_reversed;
598 i_adj_faces->used += invalid_adj_faces->used;
599 MEM_freeN(invalid_adj_faces->faces);
600 MEM_freeN(invalid_adj_faces->faces_reversed);
601 MEM_freeN(invalid_adj_faces);
602 edge_adj_faces[invalid_edge_index] = i_adj_faces;
603 /* Reset counter to continue. */
604 i = invalid_edge_index;
605 }
606 }
607 }
608 }
609
610 MEM_freeN(vert_adj_edges_len);
611
612 /* Filter duplicate faces. */
613 {
614 const int2 *edge = orig_edges.data();
615 /* Iterate over edges and only check the faces around an edge for duplicates
616 * (performance optimization). */
617 for (uint i = 0; i < edges_num; i++, edge++) {
618 if (edge_adj_faces_len[i] > 0) {
619 const OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
620 uint adj_len = adj_faces->faces_len;
621 /* Not that #adj_len doesn't need to equal edge_adj_faces_len anymore
622 * because #adj_len is shared when a face got collapsed to an edge. */
623 if (adj_len > 1) {
624 /* For each face pair check if they have equal verts. */
625 for (uint j = 0; j < adj_len; j++) {
626 const uint face = adj_faces->faces[j];
627 const int j_loopstart = orig_faces[face].start();
628 const int totloop = orig_faces[face].size();
629 const uint j_first_v = vm[orig_corner_verts[j_loopstart]];
630 for (uint k = j + 1; k < adj_len; k++) {
631 if (orig_faces[adj_faces->faces[k]].size() != totloop) {
632 continue;
633 }
634 /* Find first face first loop vert in second face loops. */
635 const int k_loopstart = orig_faces[adj_faces->faces[k]].start();
636 int l;
637 {
638 const int *corner_vert = &orig_corner_verts[k_loopstart];
639 for (l = 0; l < totloop && vm[*corner_vert] != j_first_v; l++, corner_vert++) {
640 /* Pass. */
641 }
642 }
643 if (l == totloop) {
644 continue;
645 }
646 /* Check if all following loops have equal verts. */
647 const bool reversed = adj_faces->faces_reversed[j] != adj_faces->faces_reversed[k];
648 const int count_dir = reversed ? -1 : 1;
649 bool has_diff = false;
650 for (int m = 0, n = l + totloop; m < totloop && !has_diff; m++, n += count_dir) {
651 const int vert = orig_corner_verts[j_loopstart + m];
652 has_diff = has_diff ||
653 vm[vert] != vm[orig_corner_verts[k_loopstart + n % totloop]];
654 }
655 /* If the faces are equal, discard one (j). */
656 if (!has_diff) {
657 uint del_loops = 0;
658 for (uint m = 0; m < totloop; m++) {
659 const int e = orig_corner_edges[j_loopstart + m];
660 OldEdgeFaceRef *e_adj_faces = edge_adj_faces[e];
661 if (e_adj_faces) {
662 uint face_index = j;
663 uint *e_adj_faces_faces = e_adj_faces->faces;
664 bool *e_adj_faces_reversed = e_adj_faces->faces_reversed;
665 const uint faces_len = e_adj_faces->faces_len;
666 if (e_adj_faces_faces != adj_faces->faces) {
667 /* Find index of e in #adj_faces. */
668 for (face_index = 0;
669 face_index < faces_len && e_adj_faces_faces[face_index] != face;
670 face_index++)
671 {
672 /* Pass. */
673 }
674 /* If not found. */
675 if (face_index == faces_len) {
676 continue;
677 }
678 }
679 else {
680 /* If we shrink #edge_adj_faces[i] we need to update this field. */
681 adj_len--;
682 }
683 memmove(e_adj_faces_faces + face_index,
684 e_adj_faces_faces + face_index + 1,
685 (faces_len - face_index - 1) * sizeof(*e_adj_faces_faces));
686 memmove(e_adj_faces_reversed + face_index,
687 e_adj_faces_reversed + face_index + 1,
688 (faces_len - face_index - 1) * sizeof(*e_adj_faces_reversed));
689 e_adj_faces->faces_len--;
690 if (edge_adj_faces_len[e] > 0) {
691 edge_adj_faces_len[e]--;
692 if (edge_adj_faces_len[e] == 0) {
693 e_adj_faces->used--;
694 edge_adj_faces[e] = nullptr;
695 }
696 }
697 else if (e_adj_faces->used > 1) {
698 for (uint n = 0; n < edges_num; n++) {
699 if (edge_adj_faces[n] == e_adj_faces && edge_adj_faces_len[n] > 0) {
700 edge_adj_faces_len[n]--;
701 if (edge_adj_faces_len[n] == 0) {
702 edge_adj_faces[n]->used--;
703 edge_adj_faces[n] = nullptr;
704 }
705 break;
706 }
707 }
708 }
709 del_loops++;
710 }
711 }
712 if (do_shell) {
713 new_faces_num -= 2;
714 new_loops_num -= 2 * uint(del_loops);
715 }
716 break;
717 }
718 }
719 }
720 }
721 }
722 }
723 }
724
725 /* Create #NewEdgeRef array. */
726 {
727 for (uint i = 0; i < edges_num; i++) {
728 const int2 &edge = orig_edges[i];
729 const uint v1 = vm[edge[0]];
730 const uint v2 = vm[edge[1]];
731 if (edge_adj_faces_len[i] > 0) {
732 if (LIKELY(orig_edge_lengths[i] > FLT_EPSILON)) {
733 sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
734 mul_v3_fl(edgedir, 1.0f / orig_edge_lengths[i]);
735 }
736 else {
737 /* Smart fallback. */
738 /* This makes merging non essential, but correct
739 * merging will still give way better results. */
740 float pos[3];
741 copy_v3_v3(pos, orig_mvert_co[v2]);
742
743 OldVertEdgeRef *link1 = vert_adj_edges[v1];
744 float v1_dir[3];
745 zero_v3(v1_dir);
746 for (int j = 0; j < link1->edges_len; j++) {
747 uint e = link1->edges[j];
748 if (edge_adj_faces_len[e] > 0 && e != i) {
749 uint other_v =
750 vm[vm[orig_edges[e][0]] == v1 ? orig_edges[e][1] : orig_edges[e][0]];
751 sub_v3_v3v3(edgedir, orig_mvert_co[other_v], pos);
752 add_v3_v3(v1_dir, edgedir);
753 }
754 }
755 OldVertEdgeRef *link2 = vert_adj_edges[v2];
756 float v2_dir[3];
757 zero_v3(v2_dir);
758 for (int j = 0; j < link2->edges_len; j++) {
759 uint e = link2->edges[j];
760 if (edge_adj_faces_len[e] > 0 && e != i) {
761 uint other_v =
762 vm[vm[orig_edges[e][0]] == v2 ? orig_edges[e][1] : orig_edges[e][0]];
763 sub_v3_v3v3(edgedir, orig_mvert_co[other_v], pos);
764 add_v3_v3(v2_dir, edgedir);
765 }
766 }
767 sub_v3_v3v3(edgedir, v2_dir, v1_dir);
768 float len = normalize_v3(edgedir);
769 if (len == 0.0f) {
770 edgedir[0] = 0.0f;
771 edgedir[1] = 0.0f;
772 edgedir[2] = 1.0f;
773 }
774 }
775
776 OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
777 const uint adj_len = adj_faces->faces_len;
778 const uint *adj_faces_faces = adj_faces->faces;
779 const bool *adj_faces_reversed = adj_faces->faces_reversed;
780 uint new_edges_len = 0;
781 FaceKeyPair *sorted_faces = static_cast<FaceKeyPair *>(
782 MEM_malloc_arrayN(adj_len, sizeof(*sorted_faces), __func__));
783 if (adj_len > 1) {
784 new_edges_len = adj_len;
785 /* Get keys for sorting. */
786 float ref_nor[3] = {0, 0, 0};
787 float nor[3];
788 for (uint j = 0; j < adj_len; j++) {
789 const bool reverse = adj_faces_reversed[j];
790 const uint face_i = adj_faces_faces[j];
791 if (reverse) {
792 negate_v3_v3(nor, face_nors[face_i]);
793 }
794 else {
795 copy_v3_v3(nor, face_nors[face_i]);
796 }
797 float d = 1;
798 if (orig_faces[face_i].size() > 3) {
799 d = project_v3_v3(nor, edgedir);
800 if (LIKELY(d != 0)) {
801 d = normalize_v3(nor);
802 }
803 else {
804 d = 1;
805 }
806 }
807 if (UNLIKELY(d == 0.0f)) {
808 sorted_faces[j].angle = 0.0f;
809 }
810 else if (j == 0) {
811 copy_v3_v3(ref_nor, nor);
812 sorted_faces[j].angle = 0.0f;
813 }
814 else {
815 float angle = angle_signed_on_axis_normalized_v3v3_v3(nor, ref_nor, edgedir);
816 sorted_faces[j].angle = -angle;
817 }
818 sorted_faces[j].face = face_sides_arr + adj_faces_faces[j] * 2 +
819 (adj_faces_reversed[j] ? 1 : 0);
820 }
821 /* Sort faces by order around the edge (keep order in faces,
822 * reversed and face_angles the same). */
823 qsort(sorted_faces, adj_len, sizeof(*sorted_faces), comp_float_int_pair);
824 }
825 else {
826 new_edges_len = 2;
827 sorted_faces[0].face = face_sides_arr + adj_faces_faces[0] * 2 +
828 (adj_faces_reversed[0] ? 1 : 0);
829 if (do_rim) {
830 /* Only add the loops parallel to the edge for now. */
831 new_loops_num += 2;
832 new_faces_num++;
833 }
834 }
835
836 /* Create a list of new edges and fill it. */
837 NewEdgeRef **new_edges = static_cast<NewEdgeRef **>(
838 MEM_malloc_arrayN(new_edges_len + 1, sizeof(*new_edges), __func__));
839 new_edges[new_edges_len] = nullptr;
840 NewFaceRef *faces[2];
841 for (uint j = 0; j < new_edges_len; j++) {
842 float angle;
843 if (adj_len > 1) {
844 const uint next_j = j + 1 == adj_len ? 0 : j + 1;
845 faces[0] = sorted_faces[j].face;
846 faces[1] = sorted_faces[next_j].face->reversed ? sorted_faces[next_j].face - 1 :
847 sorted_faces[next_j].face + 1;
848 angle = sorted_faces[next_j].angle - sorted_faces[j].angle;
849 if (angle < 0) {
850 angle += 2 * M_PI;
851 }
852 }
853 else {
854 faces[0] = sorted_faces[0].face->reversed ? sorted_faces[0].face - j :
855 sorted_faces[0].face + j;
856 faces[1] = nullptr;
857 angle = 0;
858 }
859 NewEdgeRef *edge_data = static_cast<NewEdgeRef *>(
860 MEM_mallocN(sizeof(*edge_data), __func__));
861 uint edge_data_edge_index = MOD_SOLIDIFY_EMPTY_TAG;
862 if (do_shell || (adj_len == 1 && do_rim)) {
863 edge_data_edge_index = 0;
864 }
865
866 NewEdgeRef new_edge_ref{};
867 new_edge_ref.old_edge = i;
868 new_edge_ref.faces[0] = faces[0];
869 new_edge_ref.faces[1] = faces[1];
870 new_edge_ref.link_edge_groups[0] = nullptr;
871 new_edge_ref.link_edge_groups[1] = nullptr;
872 new_edge_ref.angle = angle;
873 new_edge_ref.new_edge = edge_data_edge_index;
874 *edge_data = new_edge_ref;
875
876 new_edges[j] = edge_data;
877 for (uint k = 0; k < 2; k++) {
878 if (faces[k] != nullptr) {
879 for (int l = 0; l < faces[k]->face.size(); l++) {
880 const int edge = orig_corner_edges[faces[k]->face.start() + l];
881 if (edge_adj_faces[edge] == edge_adj_faces[i]) {
882 if (edge != i && orig_edge_data_arr[edge] == nullptr) {
883 orig_edge_data_arr[edge] = new_edges;
884 }
885 faces[k]->link_edges[l] = edge_data;
886 break;
887 }
888 }
889 }
890 }
891 }
892 MEM_freeN(sorted_faces);
893 orig_edge_data_arr[i] = new_edges;
894 if (do_shell || (adj_len == 1 && do_rim)) {
895 new_edges_num += new_edges_len;
896 }
897 }
898 }
899 }
900
901 for (uint i = 0; i < edges_num; i++) {
902 if (edge_adj_faces[i]) {
903 if (edge_adj_faces[i]->used > 1) {
904 edge_adj_faces[i]->used--;
905 }
906 else {
907 MEM_freeN(edge_adj_faces[i]->faces);
908 MEM_freeN(edge_adj_faces[i]->faces_reversed);
909 MEM_freeN(edge_adj_faces[i]);
910 }
911 }
912 }
913 MEM_freeN(edge_adj_faces);
914 }
915
916 /* Create sorted edge groups for every vert. */
917 {
918 OldVertEdgeRef **adj_edges_ptr = vert_adj_edges;
919 for (uint i = 0; i < verts_num; i++, adj_edges_ptr++) {
920 if (*adj_edges_ptr != nullptr && (*adj_edges_ptr)->edges_len >= 2) {
921 EdgeGroup *edge_groups;
922
923 int eg_index = -1;
924 bool contains_long_groups = false;
925 uint topo_groups = 0;
926
927 /* Initial sorted creation. */
928 {
929 const uint *adj_edges = (*adj_edges_ptr)->edges;
930 const uint tot_adj_edges = (*adj_edges_ptr)->edges_len;
931
932 uint unassigned_edges_len = 0;
933 for (uint j = 0; j < tot_adj_edges; j++) {
934 NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]];
935 /* TODO: check where the null pointer come from,
936 * because there should not be any... */
937 if (new_edges) {
938 /* count the number of new edges around the original vert */
939 while (*new_edges) {
940 unassigned_edges_len++;
941 new_edges++;
942 }
943 }
944 }
945 NewEdgeRef **unassigned_edges = static_cast<NewEdgeRef **>(
946 MEM_malloc_arrayN(unassigned_edges_len, sizeof(*unassigned_edges), __func__));
947 for (uint j = 0, k = 0; j < tot_adj_edges; j++) {
948 NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]];
949 if (new_edges) {
950 while (*new_edges) {
951 unassigned_edges[k++] = *new_edges;
952 new_edges++;
953 }
954 }
955 }
956
957 /* An edge group will always contain min 2 edges
958 * so max edge group count can be calculated. */
959 uint edge_groups_len = unassigned_edges_len / 2;
960 edge_groups = static_cast<EdgeGroup *>(
961 MEM_calloc_arrayN(edge_groups_len + 1, sizeof(*edge_groups), __func__));
962
963 uint assigned_edges_len = 0;
964 NewEdgeRef *found_edge = nullptr;
965 uint found_edge_index = 0;
966 bool insert_at_start = false;
967 uint eg_capacity = 5;
968 NewFaceRef *eg_track_faces[2] = {nullptr, nullptr};
969 NewFaceRef *last_open_edge_track = nullptr;
970
971 while (assigned_edges_len < unassigned_edges_len) {
972 found_edge = nullptr;
973 insert_at_start = false;
974 if (eg_index >= 0 && edge_groups[eg_index].edges_len == 0) {
975 /* Called every time a new group was started in the last iteration. */
976 /* Find an unused edge to start the next group
977 * and setup variables to start creating it. */
978 uint j = 0;
979 NewEdgeRef *edge = nullptr;
980 while (!edge && j < unassigned_edges_len) {
981 edge = unassigned_edges[j++];
982 if (edge && last_open_edge_track &&
983 (edge->faces[0] != last_open_edge_track || edge->faces[1] != nullptr))
984 {
985 edge = nullptr;
986 }
987 }
988 if (!edge && last_open_edge_track) {
989 topo_groups++;
990 last_open_edge_track = nullptr;
991 edge_groups[eg_index].topo_group++;
992 j = 0;
993 while (!edge && j < unassigned_edges_len) {
994 edge = unassigned_edges[j++];
995 }
996 }
997 else if (!last_open_edge_track && eg_index > 0) {
998 topo_groups++;
999 edge_groups[eg_index].topo_group++;
1000 }
1001 BLI_assert(edge != nullptr);
1002 found_edge_index = j - 1;
1003 found_edge = edge;
1004 if (!last_open_edge_track && vm[orig_edges[edge->old_edge][0]] == i) {
1005 eg_track_faces[0] = edge->faces[0];
1006 eg_track_faces[1] = edge->faces[1];
1007 if (edge->faces[1] == nullptr) {
1008 last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 :
1009 edge->faces[0] + 1;
1010 }
1011 }
1012 else {
1013 eg_track_faces[0] = edge->faces[1];
1014 eg_track_faces[1] = edge->faces[0];
1015 }
1016 }
1017 else if (eg_index >= 0) {
1018 NewEdgeRef **edge_ptr = unassigned_edges;
1019 for (found_edge_index = 0; found_edge_index < unassigned_edges_len;
1020 found_edge_index++, edge_ptr++)
1021 {
1022 if (*edge_ptr) {
1023 NewEdgeRef *edge = *edge_ptr;
1024 if (edge->faces[0] == eg_track_faces[1]) {
1025 insert_at_start = false;
1026 eg_track_faces[1] = edge->faces[1];
1027 found_edge = edge;
1028 if (edge->faces[1] == nullptr) {
1029 edge_groups[eg_index].is_orig_closed = false;
1030 last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 :
1031 edge->faces[0] + 1;
1032 }
1033 break;
1034 }
1035 if (edge->faces[0] == eg_track_faces[0]) {
1036 insert_at_start = true;
1037 eg_track_faces[0] = edge->faces[1];
1038 found_edge = edge;
1039 if (edge->faces[1] == nullptr) {
1040 edge_groups[eg_index].is_orig_closed = false;
1041 }
1042 break;
1043 }
1044 if (edge->faces[1] != nullptr) {
1045 if (edge->faces[1] == eg_track_faces[1]) {
1046 insert_at_start = false;
1047 eg_track_faces[1] = edge->faces[0];
1048 found_edge = edge;
1049 break;
1050 }
1051 if (edge->faces[1] == eg_track_faces[0]) {
1052 insert_at_start = true;
1053 eg_track_faces[0] = edge->faces[0];
1054 found_edge = edge;
1055 break;
1056 }
1057 }
1058 }
1059 }
1060 }
1061 if (found_edge) {
1062 unassigned_edges[found_edge_index] = nullptr;
1063 assigned_edges_len++;
1064 const uint needed_capacity = edge_groups[eg_index].edges_len + 1;
1065 if (needed_capacity > eg_capacity) {
1066 eg_capacity = needed_capacity + 1;
1067 NewEdgeRef **new_eg = static_cast<NewEdgeRef **>(
1068 MEM_calloc_arrayN(eg_capacity, sizeof(*new_eg), __func__));
1069 if (insert_at_start) {
1070 memcpy(new_eg + 1,
1071 edge_groups[eg_index].edges,
1072 edge_groups[eg_index].edges_len * sizeof(*new_eg));
1073 }
1074 else {
1075 memcpy(new_eg,
1076 edge_groups[eg_index].edges,
1077 edge_groups[eg_index].edges_len * sizeof(*new_eg));
1078 }
1079 MEM_freeN(edge_groups[eg_index].edges);
1080 edge_groups[eg_index].edges = new_eg;
1081 }
1082 else if (insert_at_start) {
1083 memmove(edge_groups[eg_index].edges + 1,
1084 edge_groups[eg_index].edges,
1085 edge_groups[eg_index].edges_len * sizeof(*edge_groups[eg_index].edges));
1086 }
1087 edge_groups[eg_index].edges[insert_at_start ? 0 : edge_groups[eg_index].edges_len] =
1088 found_edge;
1089 edge_groups[eg_index].edges_len++;
1090 if (edge_groups[eg_index].edges[edge_groups[eg_index].edges_len - 1]->faces[1] !=
1091 nullptr)
1092 {
1093 last_open_edge_track = nullptr;
1094 }
1095 if (edge_groups[eg_index].edges_len > 3) {
1096 contains_long_groups = true;
1097 }
1098 }
1099 else {
1100 /* called on first iteration to clean up the eg_index = -1 and start the first group,
1101 * or when the current group is found to be complete (no new found_edge) */
1102 eg_index++;
1103 BLI_assert(eg_index < edge_groups_len);
1104 eg_capacity = 5;
1105 NewEdgeRef **edges = static_cast<NewEdgeRef **>(
1106 MEM_calloc_arrayN(eg_capacity, sizeof(*edges), __func__));
1107
1108 EdgeGroup edge_group{};
1109 edge_group.valid = true;
1110 edge_group.edges = edges;
1111 edge_group.edges_len = 0;
1112 edge_group.open_face_edge = MOD_SOLIDIFY_EMPTY_TAG;
1113 edge_group.is_orig_closed = true;
1114 edge_group.is_even_split = false;
1115 edge_group.split = 0;
1116 edge_group.is_singularity = false;
1117 edge_group.topo_group = topo_groups;
1118 zero_v3(edge_group.co);
1119 zero_v3(edge_group.no);
1120 edge_group.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1121 edge_groups[eg_index] = edge_group;
1122
1123 eg_track_faces[0] = nullptr;
1124 eg_track_faces[1] = nullptr;
1125 }
1126 }
1127 /* #eg_index is the number of groups from here on. */
1128 eg_index++;
1129 /* #topo_groups is the number of topo groups from here on. */
1130 topo_groups++;
1131
1132 MEM_freeN(unassigned_edges);
1133
1134 /* TODO: reshape the edge_groups array to its actual size
1135 * after writing is finished to save on memory. */
1136 }
1137
1138 /* Split of long self intersection groups */
1139 {
1140 uint splits = 0;
1141 if (contains_long_groups) {
1142 uint add_index = 0;
1143 for (uint j = 0; j < eg_index; j++) {
1144 const uint edges_len = edge_groups[j + add_index].edges_len;
1145 if (edges_len > 3) {
1146 bool has_doubles = false;
1147 bool *doubles = static_cast<bool *>(
1148 MEM_calloc_arrayN(edges_len, sizeof(*doubles), __func__));
1149 EdgeGroup g = edge_groups[j + add_index];
1150 for (uint k = 0; k < edges_len; k++) {
1151 for (uint l = k + 1; l < edges_len; l++) {
1152 if (g.edges[k]->old_edge == g.edges[l]->old_edge) {
1153 doubles[k] = true;
1154 doubles[l] = true;
1155 has_doubles = true;
1156 }
1157 }
1158 }
1159 if (has_doubles) {
1160 const uint prior_splits = splits;
1161 const uint prior_index = add_index;
1162 int unique_start = -1;
1163 int first_unique_end = -1;
1164 int last_split = -1;
1165 int first_split = -1;
1166 bool first_even_split = false;
1167 uint real_k = 0;
1168 while (real_k < edges_len ||
1169 (g.is_orig_closed &&
1170 (real_k <=
1171 (first_unique_end == -1 ? 0 : first_unique_end) + int(edges_len) ||
1172 first_split != last_split)))
1173 {
1174 const uint k = real_k % edges_len;
1175 if (!doubles[k]) {
1176 if (first_unique_end != -1 && unique_start == -1) {
1177 unique_start = int(real_k);
1178 }
1179 }
1180 else if (first_unique_end == -1) {
1181 first_unique_end = int(k);
1182 }
1183 else if (unique_start != -1) {
1184 const uint split = ((uint(unique_start) + real_k + 1) / 2) % edges_len;
1185 const bool is_even_split = ((uint(unique_start) + real_k) & 1);
1186 if (last_split != -1) {
1187 /* Override g on first split (no insert). */
1188 if (prior_splits != splits) {
1189 memmove(edge_groups + j + add_index + 1,
1190 edge_groups + j + add_index,
1191 (uint(eg_index) - j) * sizeof(*edge_groups));
1192 add_index++;
1193 }
1194 if (last_split > split) {
1195 const uint edges_len_group = (split + edges_len) - uint(last_split);
1196 NewEdgeRef **edges = static_cast<NewEdgeRef **>(
1197 MEM_malloc_arrayN(edges_len_group, sizeof(*edges), __func__));
1198 memcpy(edges,
1199 g.edges + last_split,
1200 (edges_len - uint(last_split)) * sizeof(*edges));
1201 memcpy(edges + (edges_len - uint(last_split)),
1202 g.edges,
1203 split * sizeof(*edges));
1204
1205 EdgeGroup edge_group{};
1206 edge_group.valid = true;
1207 edge_group.edges = edges;
1208 edge_group.edges_len = edges_len_group;
1209 edge_group.open_face_edge = MOD_SOLIDIFY_EMPTY_TAG;
1210 edge_group.is_orig_closed = g.is_orig_closed;
1211 edge_group.is_even_split = is_even_split;
1212 edge_group.split = add_index - prior_index + 1 + uint(!g.is_orig_closed);
1213 edge_group.is_singularity = false;
1214 edge_group.topo_group = g.topo_group;
1215 zero_v3(edge_group.co);
1216 zero_v3(edge_group.no);
1217 edge_group.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1218 edge_groups[j + add_index] = edge_group;
1219 }
1220 else {
1221 const uint edges_len_group = split - uint(last_split);
1222 NewEdgeRef **edges = static_cast<NewEdgeRef **>(
1223 MEM_malloc_arrayN(edges_len_group, sizeof(*edges), __func__));
1224 memcpy(edges, g.edges + last_split, edges_len_group * sizeof(*edges));
1225
1226 EdgeGroup edge_group{};
1227 edge_group.valid = true;
1228 edge_group.edges = edges;
1229 edge_group.edges_len = edges_len_group;
1230 edge_group.open_face_edge = MOD_SOLIDIFY_EMPTY_TAG;
1231 edge_group.is_orig_closed = g.is_orig_closed;
1232 edge_group.is_even_split = is_even_split;
1233 edge_group.split = add_index - prior_index + 1 + uint(!g.is_orig_closed);
1234 edge_group.is_singularity = false;
1235 edge_group.topo_group = g.topo_group;
1236 zero_v3(edge_group.co);
1237 zero_v3(edge_group.no);
1238 edge_group.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1239 edge_groups[j + add_index] = edge_group;
1240 }
1241 splits++;
1242 }
1243 last_split = int(split);
1244 if (first_split == -1) {
1245 first_split = int(split);
1246 first_even_split = is_even_split;
1247 }
1248 unique_start = -1;
1249 }
1250 real_k++;
1251 }
1252 if (first_split != -1) {
1253 if (!g.is_orig_closed) {
1254 if (prior_splits != splits) {
1255 memmove(edge_groups + (j + prior_index + 1),
1256 edge_groups + (j + prior_index),
1257 (uint(eg_index) + add_index - (j + prior_index)) *
1258 sizeof(*edge_groups));
1259 memmove(edge_groups + (j + add_index + 2),
1260 edge_groups + (j + add_index + 1),
1261 (uint(eg_index) - j) * sizeof(*edge_groups));
1262 add_index++;
1263 }
1264 else {
1265 memmove(edge_groups + (j + add_index + 2),
1266 edge_groups + (j + add_index + 1),
1267 (uint(eg_index) - j - 1) * sizeof(*edge_groups));
1268 }
1269 NewEdgeRef **edges = static_cast<NewEdgeRef **>(
1270 MEM_malloc_arrayN(uint(first_split), sizeof(*edges), __func__));
1271 memcpy(edges, g.edges, uint(first_split) * sizeof(*edges));
1272
1273 EdgeGroup edge_group_a{};
1274 edge_group_a.valid = true;
1275 edge_group_a.edges = edges;
1276 edge_group_a.edges_len = uint(first_split);
1277 edge_group_a.open_face_edge = MOD_SOLIDIFY_EMPTY_TAG;
1278 edge_group_a.is_orig_closed = g.is_orig_closed;
1279 edge_group_a.is_even_split = first_even_split;
1280 edge_group_a.split = 1;
1281 edge_group_a.is_singularity = false;
1282 edge_group_a.topo_group = g.topo_group;
1283 zero_v3(edge_group_a.co);
1284 zero_v3(edge_group_a.no);
1285 edge_group_a.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1286 edge_groups[j + prior_index] = edge_group_a;
1287
1288 add_index++;
1289 splits++;
1290 edges = static_cast<NewEdgeRef **>(MEM_malloc_arrayN(
1291 edges_len - uint(last_split), sizeof(*edges), __func__));
1292 memcpy(edges,
1293 g.edges + last_split,
1294 (edges_len - uint(last_split)) * sizeof(*edges));
1295
1296 EdgeGroup edge_group_b{};
1297 edge_group_b.valid = true;
1298 edge_group_b.edges = edges;
1299 edge_group_b.edges_len = (edges_len - uint(last_split));
1300 edge_group_b.open_face_edge = MOD_SOLIDIFY_EMPTY_TAG;
1301 edge_group_b.is_orig_closed = g.is_orig_closed;
1302 edge_group_b.is_even_split = false;
1303 edge_group_b.split = add_index - prior_index + 1;
1304 edge_group_b.is_singularity = false;
1305 edge_group_b.topo_group = g.topo_group;
1306 zero_v3(edge_group_b.co);
1307 zero_v3(edge_group_b.no);
1308 edge_group_b.new_vert = MOD_SOLIDIFY_EMPTY_TAG;
1309 edge_groups[j + add_index] = edge_group_b;
1310 }
1311 if (prior_splits != splits) {
1312 MEM_freeN(g.edges);
1313 }
1314 }
1315 if (first_unique_end != -1 && prior_splits == splits) {
1316 has_singularities = true;
1317 edge_groups[j + add_index].is_singularity = true;
1318 }
1319 }
1320 MEM_freeN(doubles);
1321 }
1322 }
1323 }
1324 }
1325
1326 orig_vert_groups_arr[i] = edge_groups;
1327 /* Count new edges, loops, faces and add to link_edge_groups. */
1328 {
1329 uint new_verts = 0;
1330 bool contains_open_splits = false;
1331 uint open_edges = 0;
1332 uint contains_splits = 0;
1333 uint last_added = 0;
1334 uint first_added = 0;
1335 bool first_set = false;
1336 for (EdgeGroup *g = edge_groups; g->valid; g++) {
1337 NewEdgeRef **e = g->edges;
1338 for (uint j = 0; j < g->edges_len; j++, e++) {
1339 const uint flip = uint(vm[orig_edges[(*e)->old_edge][1]] == i);
1340 BLI_assert(flip || vm[orig_edges[(*e)->old_edge][0]] == i);
1341 (*e)->link_edge_groups[flip] = g;
1342 }
1343 uint added = 0;
1344 if (do_shell || (do_rim && !g->is_orig_closed)) {
1345 BLI_assert(g->new_vert == MOD_SOLIDIFY_EMPTY_TAG);
1346 g->new_vert = new_verts_num++;
1347 if (do_rim || (do_shell && g->split)) {
1348 new_verts++;
1349 contains_splits += (g->split != 0);
1350 contains_open_splits |= g->split && !g->is_orig_closed;
1351 added = g->split;
1352 }
1353 }
1354 open_edges += uint(added < last_added);
1355 if (!first_set) {
1356 first_set = true;
1357 first_added = added;
1358 }
1359 last_added = added;
1360 if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) {
1361 if (new_verts > 2) {
1362 new_faces_num++;
1363 new_edges_num += new_verts;
1364 open_edges += uint(first_added < last_added);
1365 open_edges -= uint(open_edges && !contains_open_splits);
1366 if (do_shell && do_rim) {
1367 new_loops_num += new_verts * 2;
1368 }
1369 else if (do_shell) {
1370 new_loops_num += new_verts * 2 - open_edges;
1371 }
1372 else { // do_rim
1373 new_loops_num += new_verts * 2 + open_edges - contains_splits;
1374 }
1375 }
1376 else if (new_verts == 2) {
1377 new_edges_num++;
1378 new_loops_num += 2u - uint(!(do_rim && do_shell) && contains_open_splits);
1379 }
1380 new_verts = 0;
1381 contains_open_splits = false;
1382 contains_splits = 0;
1383 open_edges = 0;
1384 last_added = 0;
1385 first_added = 0;
1386 first_set = false;
1387 }
1388 }
1389 }
1390 }
1391 }
1392 }
1393
1394 /* Free vert_adj_edges memory. */
1395 {
1396 uint i = 0;
1397 for (OldVertEdgeRef **p = vert_adj_edges; i < verts_num; i++, p++) {
1398 if (*p) {
1399 MEM_freeN((*p)->edges);
1400 MEM_freeN(*p);
1401 }
1402 }
1403 MEM_freeN(vert_adj_edges);
1404 }
1405
1406 /* TODO: create_regions if fix_intersections. */
1407
1408 /* General use pointer for #EdgeGroup iteration. */
1409 EdgeGroup **gs_ptr;
1410
1411 /* Calculate EdgeGroup vertex coordinates. */
1412 {
1413 float *face_weight = nullptr;
1414
1415 if (do_flat_faces) {
1416 face_weight = static_cast<float *>(
1417 MEM_malloc_arrayN(faces_num, sizeof(*face_weight), __func__));
1418
1419 for (const int i : orig_faces.index_range()) {
1420 float scalar_vgroup = 1.0f;
1421 for (const int vert : orig_corner_verts.slice(orig_faces[i])) {
1422 const MDeformVert *dv = &dvert[vert];
1423 if (defgrp_invert) {
1424 scalar_vgroup = min_ff(1.0f - BKE_defvert_find_weight(dv, defgrp_index),
1425 scalar_vgroup);
1426 }
1427 else {
1428 scalar_vgroup = min_ff(BKE_defvert_find_weight(dv, defgrp_index), scalar_vgroup);
1429 }
1430 }
1431 scalar_vgroup = offset_fac_vg + (scalar_vgroup * offset_fac_vg_inv);
1432 face_weight[i] = scalar_vgroup;
1433 }
1434 }
1435
1436 gs_ptr = orig_vert_groups_arr;
1437 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
1438 if (*gs_ptr) {
1439 for (EdgeGroup *g = *gs_ptr; g->valid; g++) {
1440 if (!g->is_singularity) {
1441 float *nor = g->no;
1442 /* During vertex position calculation, the algorithm decides if it wants to disable the
1443 * boundary fix to maintain correct thickness. If the used algorithm does not produce a
1444 * free move direction (move_nor), it can use approximate_free_direction to decide on
1445 * a movement direction based on the connected edges. */
1446 float move_nor[3] = {0, 0, 0};
1447 bool disable_boundary_fix = (smd->nonmanifold_boundary_mode ==
1449 (g->is_orig_closed || g->split));
1450 bool approximate_free_direction = false;
1451 /* Constraints Method. */
1453 NewEdgeRef *first_edge = nullptr;
1454 NewEdgeRef **edge_ptr = g->edges;
1455 /* Contains normal and offset `[nx, ny, nz, ofs]`. */
1456 float(*planes_queue)[4] = static_cast<float(*)[4]>(
1457 MEM_malloc_arrayN(g->edges_len + 1, sizeof(*planes_queue), __func__));
1458 uint queue_index = 0;
1459
1460 float fallback_nor[3];
1461 float fallback_ofs = 0.0f;
1462
1463 const bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split;
1464 for (uint k = 0; k < g->edges_len; k++, edge_ptr++) {
1465 if (!(k & 1) || (!cycle && k == g->edges_len - 1)) {
1466 NewEdgeRef *edge = *edge_ptr;
1467 for (uint l = 0; l < 2; l++) {
1468 NewFaceRef *face = edge->faces[l];
1469 if (face && (first_edge == nullptr ||
1470 (first_edge->faces[0] != face && first_edge->faces[1] != face)))
1471 {
1472 float ofs = face->reversed ? ofs_back_clamped : ofs_front_clamped;
1473 /* Use face_weight here to make faces thinner. */
1474 if (do_flat_faces) {
1475 ofs *= face_weight[face->index];
1476 }
1477
1478 if (!null_faces[face->index]) {
1479 /* And plane to the queue. */
1480 mul_v3_v3fl(planes_queue[queue_index],
1481 face_nors[face->index],
1482 face->reversed ? -1 : 1);
1483 planes_queue[queue_index++][3] = ofs;
1484 }
1485 else {
1486 /* Just use this approximate normal of the null face if there is no other
1487 * normal to use. */
1488 mul_v3_v3fl(fallback_nor, face_nors[face->index], face->reversed ? -1 : 1);
1489 fallback_ofs = ofs;
1490 }
1491 }
1492 }
1493 if ((cycle && k == 0) || (!cycle && k + 3 >= g->edges_len)) {
1494 first_edge = edge;
1495 }
1496 }
1497 }
1498 if (queue_index > 2) {
1499 /* Find the two most different normals. */
1500 float min_p = 2.0f;
1501 uint min_n0 = 0;
1502 uint min_n1 = 0;
1503 for (uint k = 0; k < queue_index; k++) {
1504 for (uint m = k + 1; m < queue_index; m++) {
1505 float p = dot_v3v3(planes_queue[k], planes_queue[m]);
1506 if (p < min_p) {
1507 min_p = p;
1508 min_n0 = k;
1509 min_n1 = m;
1510 }
1511 }
1512 }
1513 /* Put the two found normals, first in the array queue. */
1514 if (min_n1 != 0) {
1515 swap_v4_v4(planes_queue[min_n0], planes_queue[0]);
1516 swap_v4_v4(planes_queue[min_n1], planes_queue[1]);
1517 }
1518 else {
1519 swap_v4_v4(planes_queue[min_n0], planes_queue[1]);
1520 }
1521 /* Find the third most important/different normal. */
1522 min_p = 1.0f;
1523 min_n1 = 2;
1524 float max_p = -1.0f;
1525 for (uint k = 2; k < queue_index; k++) {
1526 max_p = max_ff(dot_v3v3(planes_queue[0], planes_queue[k]),
1527 dot_v3v3(planes_queue[1], planes_queue[k]));
1528 if (max_p <= min_p) {
1529 min_p = max_p;
1530 min_n1 = k;
1531 }
1532 }
1533 swap_v4_v4(planes_queue[min_n1], planes_queue[2]);
1534 }
1535 /* Remove/average duplicate normals in planes_queue. */
1536 while (queue_index > 2) {
1537 uint best_n0 = 0;
1538 uint best_n1 = 0;
1539 float best_p = -1.0f;
1540 float best_ofs_diff = 0.0f;
1541 for (uint k = 0; k < queue_index; k++) {
1542 for (uint m = k + 1; m < queue_index; m++) {
1543 float p = dot_v3v3(planes_queue[m], planes_queue[k]);
1544 float ofs_diff = fabsf(planes_queue[m][3] - planes_queue[k][3]);
1545 if (p > best_p + FLT_EPSILON || (p >= best_p && ofs_diff < best_ofs_diff)) {
1546 best_p = p;
1547 best_ofs_diff = ofs_diff;
1548 best_n0 = k;
1549 best_n1 = m;
1550 }
1551 }
1552 }
1553 /* Make sure there are no equal planes. This threshold is crucial for the
1554 * methods below to work without numerical issues. */
1555 if (best_p < 0.98f) {
1556 break;
1557 }
1558 add_v3_v3(planes_queue[best_n0], planes_queue[best_n1]);
1559 normalize_v3(planes_queue[best_n0]);
1560 planes_queue[best_n0][3] = (planes_queue[best_n0][3] + planes_queue[best_n1][3]) *
1561 0.5f;
1562 queue_index--;
1563 memmove(planes_queue + best_n1,
1564 planes_queue + best_n1 + 1,
1565 (queue_index - best_n1) * sizeof(*planes_queue));
1566 }
1567 const uint size = queue_index;
1568 /* If there is more than 2 planes at this vertex, the boundary fix should be disabled
1569 * to stay at the correct thickness for all the faces. This is not very good in
1570 * practice though, since that will almost always disable the boundary fix. Instead
1571 * introduce a threshold which decides whether the boundary fix can be used without
1572 * major thickness changes. If the following constant is 1.0, it would always
1573 * prioritize correct thickness. At 0.7 the thickness is allowed to change a bit if
1574 * necessary for the fix (~10%). Note this only applies if a boundary fix is used. */
1575 const float boundary_fix_threshold = 0.7f;
1576 if (size > 3) {
1577 /* Use the most general least squares method to find the best position. */
1578 float mat[3][3];
1579 zero_m3(mat);
1580 for (int k = 0; k < 3; k++) {
1581 for (int m = 0; m < size; m++) {
1582 madd_v3_v3fl(mat[k], planes_queue[m], planes_queue[m][k]);
1583 }
1584 /* Add a small epsilon to ensure the invert is going to work.
1585 * This addition makes the inverse more stable and the results
1586 * seem to get more precise. */
1587 mat[k][k] += 5e-5f;
1588 }
1589 /* NOTE: this matrix invert fails if there is less than 3 different normals. */
1590 invert_m3(mat);
1591 zero_v3(nor);
1592 for (int k = 0; k < size; k++) {
1593 madd_v3_v3fl(nor, planes_queue[k], planes_queue[k][3]);
1594 }
1595 mul_v3_m3v3(nor, mat, nor);
1596
1597 if (!disable_boundary_fix) {
1598 /* Figure out if the approximate boundary fix can get use here. */
1599 float greatest_angle_cos = 1.0f;
1600 for (uint k = 0; k < 2; k++) {
1601 for (uint m = 2; m < size; m++) {
1602 float p = dot_v3v3(planes_queue[m], planes_queue[k]);
1603 if (p < greatest_angle_cos) {
1604 greatest_angle_cos = p;
1605 }
1606 }
1607 }
1608 if (greatest_angle_cos > boundary_fix_threshold) {
1609 approximate_free_direction = true;
1610 }
1611 else {
1612 disable_boundary_fix = true;
1613 }
1614 }
1615 }
1616 else if (size > 1) {
1617 /* When up to 3 constraint normals are found, there is a simple solution. */
1618 const float stop_explosion = 0.999f - fabsf(smd->offset_fac) * 0.05f;
1619 const float q = dot_v3v3(planes_queue[0], planes_queue[1]);
1620 float d = 1.0f - q * q;
1621 cross_v3_v3v3(move_nor, planes_queue[0], planes_queue[1]);
1622 normalize_v3(move_nor);
1623 if (d > FLT_EPSILON * 10 && q < stop_explosion) {
1624 d = 1.0f / d;
1625 mul_v3_fl(planes_queue[0], (planes_queue[0][3] - planes_queue[1][3] * q) * d);
1626 mul_v3_fl(planes_queue[1], (planes_queue[1][3] - planes_queue[0][3] * q) * d);
1627 }
1628 else {
1629 d = 1.0f / (fabsf(q) + 1.0f);
1630 mul_v3_fl(planes_queue[0], planes_queue[0][3] * d);
1631 mul_v3_fl(planes_queue[1], planes_queue[1][3] * d);
1632 }
1633 add_v3_v3v3(nor, planes_queue[0], planes_queue[1]);
1634 if (size == 3) {
1635 d = dot_v3v3(planes_queue[2], move_nor);
1636 /* The following threshold ignores the third plane if it is almost orthogonal to
1637 * the still free direction. */
1638 if (fabsf(d) > 0.02f) {
1639 float tmp[3];
1640 madd_v3_v3v3fl(tmp, nor, planes_queue[2], -planes_queue[2][3]);
1641 mul_v3_v3fl(tmp, move_nor, dot_v3v3(planes_queue[2], tmp) / d);
1642 sub_v3_v3(nor, tmp);
1643 /* Disable boundary fix if the constraints would be majorly unsatisfied. */
1644 if (fabsf(d) > 1.0f - boundary_fix_threshold) {
1645 disable_boundary_fix = true;
1646 }
1647 }
1648 }
1649 approximate_free_direction = false;
1650 }
1651 else if (size == 1) {
1652 /* Face corner case. */
1653 mul_v3_v3fl(nor, planes_queue[0], planes_queue[0][3]);
1654 if (g->edges_len > 2) {
1655 disable_boundary_fix = true;
1656 approximate_free_direction = true;
1657 }
1658 }
1659 else {
1660 /* Fallback case for null faces. */
1661 mul_v3_v3fl(nor, fallback_nor, fallback_ofs);
1662 disable_boundary_fix = true;
1663 }
1664 MEM_freeN(planes_queue);
1665 }
1666 /* Fixed/Even Method. */
1667 else {
1668 float total_angle = 0;
1669 float total_angle_back = 0;
1670 NewEdgeRef *first_edge = nullptr;
1671 NewEdgeRef **edge_ptr = g->edges;
1672 float face_nor[3];
1673 float nor_back[3] = {0, 0, 0};
1674 bool has_back = false;
1675 bool has_front = false;
1676 bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split;
1677 for (uint k = 0; k < g->edges_len; k++, edge_ptr++) {
1678 if (!(k & 1) || (!cycle && k == g->edges_len - 1)) {
1679 NewEdgeRef *edge = *edge_ptr;
1680 for (uint l = 0; l < 2; l++) {
1681 NewFaceRef *face = edge->faces[l];
1682 if (face && (first_edge == nullptr ||
1683 (first_edge->faces[0] != face && first_edge->faces[1] != face)))
1684 {
1685 float angle = 1.0f;
1686 float ofs = face->reversed ? -ofs_back_clamped : ofs_front_clamped;
1687 /* Use face_weight here to make faces thinner. */
1688 if (do_flat_faces) {
1689 ofs *= face_weight[face->index];
1690 }
1691
1692 if (smd->nonmanifold_offset_mode ==
1694 {
1695 int corner_next = face->face.start();
1696 int corner = corner_next + (face->face.size() - 1);
1697 int corner_prev = corner - 1;
1698
1699 for (int m = 0;
1700 m < face->face.size() && vm[orig_corner_verts[corner]] != i;
1701 m++, corner_next++)
1702 {
1703 corner_prev = corner;
1704 corner = corner_next;
1705 }
1706 angle = angle_v3v3v3(orig_mvert_co[vm[orig_corner_verts[corner_prev]]],
1707 orig_mvert_co[i],
1708 orig_mvert_co[vm[orig_corner_verts[corner_next]]]);
1709 if (face->reversed) {
1710 total_angle_back += angle * ofs * ofs;
1711 }
1712 else {
1713 total_angle += angle * ofs * ofs;
1714 }
1715 }
1716 else {
1717 if (face->reversed) {
1718 total_angle_back++;
1719 }
1720 else {
1721 total_angle++;
1722 }
1723 }
1724 mul_v3_v3fl(face_nor, face_nors[face->index], angle * ofs);
1725 if (face->reversed) {
1726 add_v3_v3(nor_back, face_nor);
1727 has_back = true;
1728 }
1729 else {
1730 add_v3_v3(nor, face_nor);
1731 has_front = true;
1732 }
1733 }
1734 }
1735 if ((cycle && k == 0) || (!cycle && k + 3 >= g->edges_len)) {
1736 first_edge = edge;
1737 }
1738 }
1739 }
1740
1741 /* Set normal length with selected method. */
1743 if (has_front) {
1744 float length_sq = len_squared_v3(nor);
1745 if (LIKELY(length_sq > FLT_EPSILON)) {
1746 mul_v3_fl(nor, total_angle / length_sq);
1747 }
1748 }
1749 if (has_back) {
1750 float length_sq = len_squared_v3(nor_back);
1751 if (LIKELY(length_sq > FLT_EPSILON)) {
1752 mul_v3_fl(nor_back, total_angle_back / length_sq);
1753 }
1754 if (!has_front) {
1755 copy_v3_v3(nor, nor_back);
1756 }
1757 }
1758 if (has_front && has_back) {
1759 float nor_length = len_v3(nor);
1760 float nor_back_length = len_v3(nor_back);
1761 float q = dot_v3v3(nor, nor_back);
1762 if (LIKELY(fabsf(q) > FLT_EPSILON)) {
1763 q /= nor_length * nor_back_length;
1764 }
1765 float d = 1.0f - q * q;
1766 if (LIKELY(d > FLT_EPSILON)) {
1767 d = 1.0f / d;
1768 if (LIKELY(nor_length > FLT_EPSILON)) {
1769 mul_v3_fl(nor, (1 - nor_back_length * q / nor_length) * d);
1770 }
1771 if (LIKELY(nor_back_length > FLT_EPSILON)) {
1772 mul_v3_fl(nor_back, (1 - nor_length * q / nor_back_length) * d);
1773 }
1774 add_v3_v3(nor, nor_back);
1775 }
1776 else {
1777 mul_v3_fl(nor, 0.5f);
1778 mul_v3_fl(nor_back, 0.5f);
1779 add_v3_v3(nor, nor_back);
1780 }
1781 }
1782 }
1783 else {
1784 if (has_front && total_angle > FLT_EPSILON) {
1785 mul_v3_fl(nor, 1.0f / total_angle);
1786 }
1787 if (has_back && total_angle_back > FLT_EPSILON) {
1788 mul_v3_fl(nor_back, 1.0f / total_angle_back);
1789 add_v3_v3(nor, nor_back);
1790 if (has_front && total_angle > FLT_EPSILON) {
1791 mul_v3_fl(nor, 0.5f);
1792 }
1793 }
1794 }
1795 /* Set move_nor for boundary fix. */
1796 if (!disable_boundary_fix && g->edges_len > 2) {
1797 approximate_free_direction = true;
1798 }
1799 else {
1800 disable_boundary_fix = true;
1801 }
1802 }
1803 if (approximate_free_direction) {
1804 /* Set move_nor for boundary fix. */
1805 NewEdgeRef **edge_ptr = g->edges + 1;
1806 float tmp[3];
1807 int k;
1808 for (k = 1; k + 1 < g->edges_len; k++, edge_ptr++) {
1809 const int2 &edge = orig_edges[(*edge_ptr)->old_edge];
1811 tmp, orig_mvert_co[vm[edge[0]] == i ? edge[1] : edge[0]], orig_mvert_co[i]);
1812 add_v3_v3(move_nor, tmp);
1813 }
1814 if (k == 1) {
1815 disable_boundary_fix = true;
1816 }
1817 else {
1818 disable_boundary_fix = normalize_v3(move_nor) == 0.0f;
1819 }
1820 }
1821 /* Fix boundary verts. */
1822 if (!disable_boundary_fix) {
1823 /* Constraint normal, nor * constr_nor == 0 after this fix. */
1824 float constr_nor[3];
1825 const int2 &e0_edge = orig_edges[g->edges[0]->old_edge];
1826 const int2 &e1_edge = orig_edges[g->edges[g->edges_len - 1]->old_edge];
1827 float e0[3];
1828 float e1[3];
1829 sub_v3_v3v3(e0,
1830 orig_mvert_co[vm[e0_edge[0]] == i ? e0_edge[1] : e0_edge[0]],
1831 orig_mvert_co[i]);
1832 sub_v3_v3v3(e1,
1833 orig_mvert_co[vm[e1_edge[0]] == i ? e1_edge[1] : e1_edge[0]],
1834 orig_mvert_co[i]);
1836 cross_v3_v3v3(constr_nor, e0, e1);
1837 normalize_v3(constr_nor);
1838 }
1839 else {
1842 float f0[3];
1843 float f1[3];
1844 if (g->edges[0]->faces[0]->reversed) {
1845 negate_v3_v3(f0, face_nors[g->edges[0]->faces[0]->index]);
1846 }
1847 else {
1848 copy_v3_v3(f0, face_nors[g->edges[0]->faces[0]->index]);
1849 }
1850 if (g->edges[g->edges_len - 1]->faces[0]->reversed) {
1851 negate_v3_v3(f1, face_nors[g->edges[g->edges_len - 1]->faces[0]->index]);
1852 }
1853 else {
1854 copy_v3_v3(f1, face_nors[g->edges[g->edges_len - 1]->faces[0]->index]);
1855 }
1856 float n0[3];
1857 float n1[3];
1858 cross_v3_v3v3(n0, e0, f0);
1859 cross_v3_v3v3(n1, f1, e1);
1860 normalize_v3(n0);
1861 normalize_v3(n1);
1862 add_v3_v3v3(constr_nor, n0, n1);
1863 normalize_v3(constr_nor);
1864 }
1865 float d = dot_v3v3(constr_nor, move_nor);
1866 /* Only allow the thickness to increase about 10 times. */
1867 if (fabsf(d) > 0.1f) {
1868 mul_v3_fl(move_nor, dot_v3v3(constr_nor, nor) / d);
1869 sub_v3_v3(nor, move_nor);
1870 }
1871 }
1872 float scalar_vgroup = 1;
1873 /* Use vertex group. */
1874 if (dvert && !do_flat_faces) {
1875 const MDeformVert *dv = &dvert[i];
1876 if (defgrp_invert) {
1877 scalar_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
1878 }
1879 else {
1880 scalar_vgroup = BKE_defvert_find_weight(dv, defgrp_index);
1881 }
1882 scalar_vgroup = offset_fac_vg + (scalar_vgroup * offset_fac_vg_inv);
1883 }
1884 /* Do clamping. */
1885 if (do_clamp) {
1886 if (do_angle_clamp) {
1887 if (g->edges_len > 2) {
1888 float min_length = 0;
1889 float angle = 0.5f * M_PI;
1890 uint k = 0;
1891 for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
1892 float length = orig_edge_lengths[(*p)->old_edge];
1893 float e_ang = (*p)->angle;
1894 if (e_ang > angle) {
1895 angle = e_ang;
1896 }
1897 if (length < min_length || k == 0) {
1898 min_length = length;
1899 }
1900 }
1901 float cos_ang = cosf(angle * 0.5f);
1902 if (cos_ang > 0) {
1903 float max_off = min_length * 0.5f / cos_ang;
1904 if (max_off < offset * 0.5f) {
1905 scalar_vgroup *= max_off / offset * 2;
1906 }
1907 }
1908 }
1909 }
1910 else {
1911 float min_length = 0;
1912 uint k = 0;
1913 for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
1914 float length = orig_edge_lengths[(*p)->old_edge];
1915 if (length < min_length || k == 0) {
1916 min_length = length;
1917 }
1918 }
1919 if (min_length < offset) {
1920 scalar_vgroup *= min_length / offset;
1921 }
1922 }
1923 }
1924 mul_v3_fl(nor, scalar_vgroup);
1925 add_v3_v3v3(g->co, nor, orig_mvert_co[i]);
1926 }
1927 else {
1928 copy_v3_v3(g->co, orig_mvert_co[i]);
1929 }
1930 }
1931 }
1932 }
1933
1934 if (do_flat_faces) {
1935 MEM_freeN(face_weight);
1936 }
1937 }
1938
1939 MEM_freeN(orig_mvert_co);
1940 if (null_faces) {
1941 MEM_freeN(null_faces);
1942 }
1943
1944 /* TODO: create vertdata for intersection fixes (intersection fixing per topology region). */
1945
1946 /* Correction for adjacent one sided groups around a vert to
1947 * prevent edge duplicates and null faces. */
1948 uint(*singularity_edges)[2] = nullptr;
1949 uint totsingularity = 0;
1950 if (has_singularities) {
1951 has_singularities = false;
1952 uint i = 0;
1953 uint singularity_edges_len = 1;
1954 singularity_edges = static_cast<uint(*)[2]>(
1955 MEM_malloc_arrayN(singularity_edges_len, sizeof(*singularity_edges), __func__));
1956 for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < edges_num; i++, new_edges++) {
1957 if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) {
1958 for (NewEdgeRef **l = *new_edges; *l; l++) {
1959 if ((*l)->link_edge_groups[0]->is_singularity &&
1960 (*l)->link_edge_groups[1]->is_singularity)
1961 {
1962 const uint v1 = (*l)->link_edge_groups[0]->new_vert;
1963 const uint v2 = (*l)->link_edge_groups[1]->new_vert;
1964 bool exists_already = false;
1965 uint j = 0;
1966 for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) {
1967 if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) {
1968 exists_already = true;
1969 break;
1970 }
1971 }
1972 if (!exists_already) {
1973 has_singularities = true;
1974 if (singularity_edges_len <= totsingularity) {
1975 singularity_edges_len = totsingularity + 1;
1976 singularity_edges = static_cast<uint(*)[2]>(
1977 MEM_reallocN_id(singularity_edges,
1978 singularity_edges_len * sizeof(*singularity_edges),
1979 __func__));
1980 }
1981 singularity_edges[totsingularity][0] = v1;
1982 singularity_edges[totsingularity][1] = v2;
1983 totsingularity++;
1984 if (edge_adj_faces_len[i] == 1 && do_rim) {
1985 new_loops_num -= 2;
1986 new_faces_num--;
1987 }
1988 }
1989 else {
1990 new_edges_num--;
1991 }
1992 }
1993 }
1994 }
1995 }
1996 }
1997
1998 /* Create Mesh *result with proper capacity. */
2000 mesh, int(new_verts_num), int(new_edges_num), int(new_faces_num), int(new_loops_num));
2001
2002 blender::MutableSpan<float3> vert_positions = result->vert_positions_for_write();
2003 blender::MutableSpan<int2> edges = result->edges_for_write();
2004 blender::MutableSpan<int> face_offsets = result->face_offsets_for_write();
2005 blender::MutableSpan<int> corner_verts = result->corner_verts_for_write();
2006 blender::MutableSpan<int> corner_edges = result->corner_edges_for_write();
2007
2008 int *origindex_edge = static_cast<int *>(
2009 CustomData_get_layer_for_write(&result->edge_data, CD_ORIGINDEX, result->edges_num));
2010 int *origindex_face = static_cast<int *>(
2011 CustomData_get_layer_for_write(&result->face_data, CD_ORIGINDEX, result->faces_num));
2012
2013 float *result_edge_bweight = static_cast<float *>(CustomData_get_layer_named_for_write(
2014 &result->edge_data, CD_PROP_FLOAT, "bevel_weight_edge", result->edges_num));
2015 if (!result_edge_bweight && (bevel_convex != 0.0f || orig_vert_bweight != nullptr)) {
2016 result_edge_bweight = static_cast<float *>(CustomData_add_layer_named(&result->edge_data,
2019 result->edges_num,
2020 "bevel_weight_edge"));
2021 }
2022
2023 /* Checks that result has dvert data. */
2024 MDeformVert *dst_dvert = nullptr;
2025 if (shell_defgrp_index != -1 || rim_defgrp_index != -1) {
2026 dst_dvert = result->deform_verts_for_write().data();
2027 }
2028
2029 /* Get vertex crease layer and ensure edge creases are active if vertex creases are found, since
2030 * they will introduce edge creases in the used custom interpolation method. */
2031 const float *vertex_crease = static_cast<const float *>(
2032 CustomData_get_layer_named(&mesh->vert_data, CD_PROP_FLOAT, "crease_vert"));
2033 float *result_edge_crease = nullptr;
2034 if (vertex_crease || orig_edge_crease) {
2035 result_edge_crease = static_cast<float *>(CustomData_get_layer_named_for_write(
2036 &result->edge_data, CD_PROP_FLOAT, "crease_edge", result->edges_num));
2037 if (!result_edge_crease) {
2038 result_edge_crease = (float *)CustomData_add_layer_named(
2039 &result->edge_data, CD_PROP_FLOAT, CD_SET_DEFAULT, result->edges_num, "crease_edge");
2040 }
2041 /* delete all vertex creases in the result if a rim is used. */
2042 if (do_rim) {
2043 CustomData_free_layer_named(&result->vert_data, "crease_vert", result->verts_num);
2044 }
2045 }
2046
2047 /* Make_new_verts. */
2048 {
2049 gs_ptr = orig_vert_groups_arr;
2050 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
2051 EdgeGroup *gs = *gs_ptr;
2052 if (gs) {
2053 for (EdgeGroup *g = gs; g->valid; g++) {
2054 if (g->new_vert != MOD_SOLIDIFY_EMPTY_TAG) {
2056 &mesh->vert_data, &result->vert_data, int(i), int(g->new_vert), 1);
2057 copy_v3_v3(vert_positions[g->new_vert], g->co);
2058 }
2059 }
2060 }
2061 }
2062 }
2063
2064 /* Make edges. */
2065 {
2066 uint i = 0;
2067 edge_index += totsingularity;
2068 for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < edges_num; i++, new_edges++) {
2069 if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) {
2070 for (NewEdgeRef **l = *new_edges; *l; l++) {
2071 if ((*l)->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
2072 const uint v1 = (*l)->link_edge_groups[0]->new_vert;
2073 const uint v2 = (*l)->link_edge_groups[1]->new_vert;
2074 uint insert = edge_index;
2075 if (has_singularities && ((*l)->link_edge_groups[0]->is_singularity &&
2076 (*l)->link_edge_groups[1]->is_singularity))
2077 {
2078 uint j = 0;
2079 for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) {
2080 if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) {
2081 insert = j;
2082 break;
2083 }
2084 }
2085 BLI_assert(insert == j);
2086 }
2087 else {
2088 edge_index++;
2089 }
2090 CustomData_copy_data(&mesh->edge_data, &result->edge_data, int(i), int(insert), 1);
2093 edges[insert][0] = v1;
2094 edges[insert][1] = v2;
2095 if (result_edge_crease) {
2096 result_edge_crease[insert] = orig_edge_crease ? orig_edge_crease[(*l)->old_edge] :
2097 0.0f;
2098 }
2099 if (result_edge_bweight) {
2100 result_edge_bweight[insert] = orig_edge_bweight ? orig_edge_bweight[(*l)->old_edge] :
2101 0.0f;
2102 }
2103 if (bevel_convex != 0.0f && (*l)->faces[1] != nullptr) {
2104 result_edge_bweight[insert] = clamp_f(
2105 result_edge_bweight[insert] +
2106 ((*l)->angle > M_PI + FLT_EPSILON ?
2107 clamp_f(bevel_convex, 0.0f, 1.0f) :
2108 ((*l)->angle < M_PI - FLT_EPSILON ? clamp_f(bevel_convex, -1.0f, 0.0f) :
2109 0)),
2110 0.0f,
2111 1.0f);
2112 }
2113 (*l)->new_edge = insert;
2114 }
2115 }
2116 }
2117 }
2118 }
2119 if (singularity_edges) {
2120 MEM_freeN(singularity_edges);
2121 }
2122
2123 /* DEBUG CODE FOR BUG-FIXING (can not be removed because every bug-fix needs this badly!). */
2124#if 0
2125 {
2126 /* this code will output the content of orig_vert_groups_arr.
2127 * in orig_vert_groups_arr these conditions must be met for every vertex:
2128 * - new_edge value should have no duplicates
2129 * - every old_edge value should appear twice
2130 * - every group should have at least two members (edges)
2131 * NOTE: that there can be vertices that only have one group. They are called singularities.
2132 * These vertices will only have one side (there is no way of telling apart front
2133 * from back like on a mobius strip)
2134 */
2135
2136 /* Debug output format:
2137 * <original vertex id>:
2138 * {
2139 * { <old edge id>/<new edge id>, } \
2140 * (tg:<topology group id>)(s:<is split group>,c:<is closed group (before splitting)>)
2141 * }
2142 */
2143 gs_ptr = orig_vert_groups_arr;
2144 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
2145 EdgeGroup *gs = *gs_ptr;
2146 /* check if the vertex is present (may be dissolved because of proximity) */
2147 if (gs) {
2148 printf("%d:\n", i);
2149 for (EdgeGroup *g = gs; g->valid; g++) {
2150 NewEdgeRef **e = g->edges;
2151 for (uint j = 0; j < g->edges_len; j++, e++) {
2152 printf("%u/%d, ", (*e)->old_edge, int(*e)->new_edge);
2153 }
2154 printf("(tg:%u)(s:%u,c:%d)\n", g->topo_group, g->split, g->is_orig_closed);
2155 }
2156 }
2157 }
2158 }
2159#endif
2160 const bke::AttributeAccessor src_attributes = mesh->attributes();
2161 const VArraySpan src_material_index = *src_attributes.lookup<int>("material_index",
2162 bke::AttrDomain::Face);
2163 bke::MutableAttributeAccessor dst_attributes = result->attributes_for_write();
2164 bke::SpanAttributeWriter dst_material_index = dst_attributes.lookup_or_add_for_write_span<int>(
2165 "material_index", bke::AttrDomain::Face);
2166
2167 /* Make boundary edges/faces. */
2168 {
2169 gs_ptr = orig_vert_groups_arr;
2170 for (uint i = 0; i < verts_num; i++, gs_ptr++) {
2171 EdgeGroup *gs = *gs_ptr;
2172 if (gs) {
2173 EdgeGroup *g = gs;
2174 EdgeGroup *g2 = gs;
2175 EdgeGroup *last_g = nullptr;
2176 EdgeGroup *first_g = nullptr;
2177 float mv_crease = vertex_crease ? vertex_crease[i] : 0.0f;
2178 float mv_bweight = orig_vert_bweight ? orig_vert_bweight[i] : 0.0f;
2179 /* Data calculation cache. */
2180 float max_crease;
2181 float last_max_crease = 0.0f;
2182 float first_max_crease = 0.0f;
2183 float max_bweight;
2184 float last_max_bweight = 0.0f;
2185 float first_max_bweight = 0.0f;
2186 for (uint j = 0; g->valid; g++) {
2187 if ((do_rim && !g->is_orig_closed) || (do_shell && g->split)) {
2188 max_crease = 0;
2189 max_bweight = 0;
2190
2191 BLI_assert(g->edges_len >= 2);
2192
2193 if (g->edges_len == 2) {
2194 if (result_edge_crease) {
2195 if (orig_edge_crease) {
2196 max_crease = min_ff(orig_edge_crease[g->edges[0]->old_edge],
2197 orig_edge_crease[g->edges[1]->old_edge]);
2198 }
2199 else {
2200 max_crease = 0.0f;
2201 }
2202 }
2203 }
2204 else {
2205 for (uint k = 1; k < g->edges_len - 1; k++) {
2206 const uint orig_edge_index = g->edges[k]->old_edge;
2207 if (result_edge_crease) {
2208 if (orig_edge_crease && orig_edge_crease[orig_edge_index] > max_crease) {
2209 max_crease = orig_edge_crease[orig_edge_index];
2210 }
2211 }
2212 if (g->edges[k]->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
2213 if (result_edge_bweight) {
2214 float bweight = result_edge_bweight[g->edges[k]->new_edge];
2215 if (bweight > max_bweight) {
2216 max_bweight = bweight;
2217 }
2218 }
2219 }
2220 }
2221 }
2222
2223 const float bweight_open_edge =
2224 orig_edge_bweight ?
2225 min_ff(orig_edge_bweight[g->edges[0]->old_edge],
2226 orig_edge_bweight[g->edges[g->edges_len - 1]->old_edge]) :
2227 0.0f;
2228 if (bweight_open_edge > 0) {
2229 max_bweight = min_ff(bweight_open_edge, max_bweight);
2230 }
2231 else {
2232 if (bevel_convex < 0.0f) {
2233 max_bweight = 0;
2234 }
2235 }
2236 if (!first_g) {
2237 first_g = g;
2238 first_max_crease = max_crease;
2239 first_max_bweight = max_bweight;
2240 }
2241 else {
2242 last_g->open_face_edge = edge_index;
2243 CustomData_copy_data(&mesh->edge_data,
2244 &result->edge_data,
2245 int(last_g->edges[0]->old_edge),
2246 int(edge_index),
2247 1);
2248 if (origindex_edge) {
2249 origindex_edge[edge_index] = ORIGINDEX_NONE;
2250 }
2251 edges[edge_index][0] = last_g->new_vert;
2252 edges[edge_index][1] = g->new_vert;
2253 if (result_edge_crease) {
2254 result_edge_crease[edge_index] = max_ff(mv_crease,
2255 min_ff(last_max_crease, max_crease));
2256 }
2257 if (result_edge_bweight) {
2258 result_edge_bweight[edge_index] = max_ff(mv_bweight,
2259 min_ff(last_max_bweight, max_bweight));
2260 }
2261 edge_index++;
2262 }
2263 last_g = g;
2264 last_max_crease = max_crease;
2265 last_max_bweight = max_bweight;
2266 j++;
2267 }
2268 if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) {
2269 if (j == 2) {
2270 last_g->open_face_edge = edge_index - 1;
2271 }
2272 if (j > 2) {
2273 CustomData_copy_data(&mesh->edge_data,
2274 &result->edge_data,
2275 int(last_g->edges[0]->old_edge),
2276 int(edge_index),
2277 1);
2278 if (origindex_edge) {
2279 origindex_edge[edge_index] = ORIGINDEX_NONE;
2280 }
2281 last_g->open_face_edge = edge_index;
2282 edges[edge_index][0] = last_g->new_vert;
2283 edges[edge_index][1] = first_g->new_vert;
2284 if (result_edge_crease) {
2285 result_edge_crease[edge_index] = max_ff(mv_crease,
2286 min_ff(last_max_crease, first_max_crease));
2287 }
2288 if (result_edge_bweight) {
2289 result_edge_bweight[edge_index] = max_ff(
2290 mv_bweight, min_ff(last_max_bweight, first_max_bweight));
2291 }
2292 edge_index++;
2293
2294 /* Loop data. */
2295 int *loops_data = static_cast<int *>(
2296 MEM_malloc_arrayN(j, sizeof(*loops_data), __func__));
2297 /* The result material index is from consensus. */
2298 short most_mat_nr = 0;
2299 uint most_mat_nr_face = 0;
2300 uint most_mat_nr_count = 0;
2301 for (short l = 0; l < mat_nrs; l++) {
2302 uint count = 0;
2303 uint face = 0;
2304 uint k = 0;
2305 for (EdgeGroup *g3 = g2; g3->valid && k < j; g3++) {
2306 if ((do_rim && !g3->is_orig_closed) || (do_shell && g3->split)) {
2307 /* Check both far ends in terms of faces of an edge group. */
2308 if ((!src_material_index.is_empty() ?
2309 src_material_index[g3->edges[0]->faces[0]->index] :
2310 0) == l)
2311 {
2312 face = g3->edges[0]->faces[0]->index;
2313 count++;
2314 }
2315 NewEdgeRef *le = g3->edges[g3->edges_len - 1];
2316 if (le->faces[1] &&
2317 (!src_material_index.is_empty() ? src_material_index[le->faces[1]->index] :
2318 0) == l)
2319 {
2320 face = le->faces[1]->index;
2321 count++;
2322 }
2323 else if (!le->faces[1] && (!src_material_index.is_empty() ?
2324 src_material_index[le->faces[0]->index] :
2325 0) == l)
2326 {
2327 face = le->faces[0]->index;
2328 count++;
2329 }
2330 k++;
2331 }
2332 }
2333 if (count > most_mat_nr_count) {
2334 most_mat_nr = l;
2335 most_mat_nr_face = face;
2336 most_mat_nr_count = count;
2337 }
2338 }
2340 &mesh->face_data, &result->face_data, int(most_mat_nr_face), int(face_index), 1);
2341 if (origindex_face) {
2342 origindex_face[face_index] = ORIGINDEX_NONE;
2343 }
2344 face_offsets[face_index] = int(loop_index);
2345 dst_material_index.span[face_index] = most_mat_nr + (g->is_orig_closed || !do_rim ?
2346 0 :
2347 mat_ofs_rim);
2348 CLAMP(dst_material_index.span[face_index], 0, mat_nr_max);
2349 face_index++;
2350
2351 for (uint k = 0; g2->valid && k < j; g2++) {
2352 if ((do_rim && !g2->is_orig_closed) || (do_shell && g2->split)) {
2353 const blender::IndexRange face = g2->edges[0]->faces[0]->face;
2354 for (int l = 0; l < face.size(); l++) {
2355 const int vert = orig_corner_verts[face[l]];
2356 if (vm[vert] == i) {
2357 loops_data[k] = face[l];
2358 break;
2359 }
2360 }
2361 k++;
2362 }
2363 }
2364
2365 if (!do_flip) {
2366 for (uint k = 0; k < j; k++) {
2368 &mesh->corner_data, &result->corner_data, loops_data[k], int(loop_index), 1);
2369 corner_verts[loop_index] = edges[edge_index - j + k][0];
2370 corner_edges[loop_index++] = edge_index - j + k;
2371 }
2372 }
2373 else {
2374 for (uint k = 1; k <= j; k++) {
2375 CustomData_copy_data(&mesh->corner_data,
2376 &result->corner_data,
2377 loops_data[j - k],
2378 int(loop_index),
2379 1);
2380 corner_verts[loop_index] = edges[edge_index - k][1];
2381 corner_edges[loop_index++] = edge_index - k;
2382 }
2383 }
2384 MEM_freeN(loops_data);
2385 }
2386 /* Reset everything for the next face. */
2387 j = 0;
2388 last_g = nullptr;
2389 first_g = nullptr;
2390 last_max_crease = 0;
2391 first_max_crease = 0;
2392 last_max_bweight = 0;
2393 first_max_bweight = 0;
2394 }
2395 }
2396 }
2397 }
2398 }
2399
2400 /* Make boundary faces. */
2401 if (do_rim) {
2402 for (uint i = 0; i < edges_num; i++) {
2403 if (edge_adj_faces_len[i] == 1 && orig_edge_data_arr[i] &&
2404 (*orig_edge_data_arr[i])->old_edge == i)
2405 {
2406 NewEdgeRef **new_edges = orig_edge_data_arr[i];
2407
2408 NewEdgeRef *edge1 = new_edges[0];
2409 NewEdgeRef *edge2 = new_edges[1];
2410 const bool v1_singularity = edge1->link_edge_groups[0]->is_singularity &&
2412 const bool v2_singularity = edge1->link_edge_groups[1]->is_singularity &&
2414 if (v1_singularity && v2_singularity) {
2415 continue;
2416 }
2417
2418 const uint orig_face_index = (*new_edges)->faces[0]->index;
2419 const blender::IndexRange face = (*new_edges)->faces[0]->face;
2420 CustomData_copy_data(&mesh->face_data,
2421 &result->face_data,
2422 int((*new_edges)->faces[0]->index),
2423 int(face_index),
2424 1);
2425 face_offsets[face_index] = int(loop_index);
2426 dst_material_index.span[face_index] = (!src_material_index.is_empty() ?
2427 src_material_index[orig_face_index] :
2428 0) +
2429 mat_ofs_rim;
2430 CLAMP(dst_material_index.span[face_index], 0, mat_nr_max);
2431 face_index++;
2432
2433 int loop1 = -1;
2434 int loop2 = -1;
2435 const uint old_v1 = vm[orig_edges[edge1->old_edge][0]];
2436 const uint old_v2 = vm[orig_edges[edge1->old_edge][1]];
2437 for (uint j = 0; j < face.size(); j++) {
2438 const int vert = orig_corner_verts[face.start() + j];
2439 if (vm[vert] == old_v1) {
2440 loop1 = face.start() + int(j);
2441 }
2442 else if (vm[vert] == old_v2) {
2443 loop2 = face.start() + int(j);
2444 }
2445 }
2446 BLI_assert(loop1 != -1 && loop2 != -1);
2447 int2 open_face_edge;
2448 uint open_face_edge_index;
2449 if (!do_flip) {
2450 if (rim_defgrp_index != -1) {
2451 BKE_defvert_ensure_index(&dst_dvert[edges[edge1->new_edge][0]], rim_defgrp_index)
2452 ->weight = 1.0f;
2453 }
2455 &mesh->corner_data, &result->corner_data, loop1, int(loop_index), 1);
2456 corner_verts[loop_index] = edges[edge1->new_edge][0];
2457 corner_edges[loop_index++] = edge1->new_edge;
2458
2459 if (!v2_singularity) {
2460 open_face_edge_index = edge1->link_edge_groups[1]->open_face_edge;
2461 if (rim_defgrp_index != -1) {
2462 BKE_defvert_ensure_index(&dst_dvert[edges[edge1->new_edge][1]], rim_defgrp_index)
2463 ->weight = 1.0f;
2464 }
2466 &mesh->corner_data, &result->corner_data, loop2, int(loop_index), 1);
2467 corner_verts[loop_index] = edges[edge1->new_edge][1];
2468 open_face_edge = edges[open_face_edge_index];
2469 if (ELEM(edges[edge2->new_edge][1], open_face_edge[0], open_face_edge[1])) {
2470 corner_edges[loop_index++] = open_face_edge_index;
2471 }
2472 else {
2473 corner_edges[loop_index++] = edge2->link_edge_groups[1]->open_face_edge;
2474 }
2475 }
2476
2477 if (rim_defgrp_index != -1) {
2478 BKE_defvert_ensure_index(&dst_dvert[edges[edge2->new_edge][1]], rim_defgrp_index)
2479 ->weight = 1.0f;
2480 }
2482 &mesh->corner_data, &result->corner_data, loop2, int(loop_index), 1);
2483 corner_verts[loop_index] = edges[edge2->new_edge][1];
2484 corner_edges[loop_index++] = edge2->new_edge;
2485
2486 if (!v1_singularity) {
2487 open_face_edge_index = edge2->link_edge_groups[0]->open_face_edge;
2488 if (rim_defgrp_index != -1) {
2489 BKE_defvert_ensure_index(&dst_dvert[edges[edge2->new_edge][0]], rim_defgrp_index)
2490 ->weight = 1.0f;
2491 }
2493 &mesh->corner_data, &result->corner_data, loop1, int(loop_index), 1);
2494 corner_verts[loop_index] = edges[edge2->new_edge][0];
2495 open_face_edge = edges[open_face_edge_index];
2496 if (ELEM(edges[edge1->new_edge][0], open_face_edge[0], open_face_edge[1])) {
2497 corner_edges[loop_index++] = open_face_edge_index;
2498 }
2499 else {
2500 corner_edges[loop_index++] = edge1->link_edge_groups[0]->open_face_edge;
2501 }
2502 }
2503 }
2504 else {
2505 if (!v1_singularity) {
2506 open_face_edge_index = edge1->link_edge_groups[0]->open_face_edge;
2507 if (rim_defgrp_index != -1) {
2508 BKE_defvert_ensure_index(&dst_dvert[edges[edge1->new_edge][0]], rim_defgrp_index)
2509 ->weight = 1.0f;
2510 }
2512 &mesh->corner_data, &result->corner_data, loop1, int(loop_index), 1);
2513 corner_verts[loop_index] = edges[edge1->new_edge][0];
2514 open_face_edge = edges[open_face_edge_index];
2515 if (ELEM(edges[edge2->new_edge][0], open_face_edge[0], open_face_edge[1])) {
2516 corner_edges[loop_index++] = open_face_edge_index;
2517 }
2518 else {
2519 corner_edges[loop_index++] = edge2->link_edge_groups[0]->open_face_edge;
2520 }
2521 }
2522
2523 if (rim_defgrp_index != -1) {
2524 BKE_defvert_ensure_index(&dst_dvert[edges[edge2->new_edge][0]], rim_defgrp_index)
2525 ->weight = 1.0f;
2526 }
2528 &mesh->corner_data, &result->corner_data, loop1, int(loop_index), 1);
2529 corner_verts[loop_index] = edges[edge2->new_edge][0];
2530 corner_edges[loop_index++] = edge2->new_edge;
2531
2532 if (!v2_singularity) {
2533 open_face_edge_index = edge2->link_edge_groups[1]->open_face_edge;
2534 if (rim_defgrp_index != -1) {
2535 BKE_defvert_ensure_index(&dst_dvert[edges[edge2->new_edge][1]], rim_defgrp_index)
2536 ->weight = 1.0f;
2537 }
2539 &mesh->corner_data, &result->corner_data, loop2, int(loop_index), 1);
2540 corner_verts[loop_index] = edges[edge2->new_edge][1];
2541 open_face_edge = edges[open_face_edge_index];
2542 if (ELEM(edges[edge1->new_edge][1], open_face_edge[0], open_face_edge[1])) {
2543 corner_edges[loop_index++] = open_face_edge_index;
2544 }
2545 else {
2546 corner_edges[loop_index++] = edge1->link_edge_groups[1]->open_face_edge;
2547 }
2548 }
2549
2550 if (rim_defgrp_index != -1) {
2551 BKE_defvert_ensure_index(&dst_dvert[edges[edge1->new_edge][1]], rim_defgrp_index)
2552 ->weight = 1.0f;
2553 }
2555 &mesh->corner_data, &result->corner_data, loop2, int(loop_index), 1);
2556 corner_verts[loop_index] = edges[edge1->new_edge][1];
2557 corner_edges[loop_index++] = edge1->new_edge;
2558 }
2559 }
2560 }
2561 }
2562
2563 /* Make faces. */
2564 if (do_shell) {
2565 NewFaceRef *fr = face_sides_arr;
2566 uint *face_loops = static_cast<uint *>(
2567 MEM_malloc_arrayN(largest_ngon * 2, sizeof(*face_loops), __func__));
2568 uint *face_verts = static_cast<uint *>(
2569 MEM_malloc_arrayN(largest_ngon * 2, sizeof(*face_verts), __func__));
2570 uint *face_edges = static_cast<uint *>(
2571 MEM_malloc_arrayN(largest_ngon * 2, sizeof(*face_edges), __func__));
2572 for (uint i = 0; i < faces_num * 2; i++, fr++) {
2573 const uint loopstart = uint(fr->face.start());
2574 uint totloop = uint(fr->face.size());
2575 uint valid_edges = 0;
2576 uint k = 0;
2577 while (totloop > 0 && (!fr->link_edges[totloop - 1] ||
2578 fr->link_edges[totloop - 1]->new_edge == MOD_SOLIDIFY_EMPTY_TAG))
2579 {
2580 totloop--;
2581 }
2582 if (totloop > 0) {
2583 NewEdgeRef *prior_edge = fr->link_edges[totloop - 1];
2584 uint prior_flip = uint(vm[orig_edges[prior_edge->old_edge][0]] ==
2585 vm[orig_corner_verts[loopstart + (totloop - 1)]]);
2586 for (uint j = 0; j < totloop; j++) {
2587 NewEdgeRef *new_edge = fr->link_edges[j];
2588 if (new_edge && new_edge->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
2589 valid_edges++;
2590 const uint flip = uint(vm[orig_edges[new_edge->old_edge][1]] ==
2591 vm[orig_corner_verts[loopstart + j]]);
2592 BLI_assert(flip || vm[orig_edges[new_edge->old_edge][0]] ==
2593 vm[orig_corner_verts[loopstart + j]]);
2594 /* The vert that's in the current loop. */
2595 const uint new_v1 = new_edge->link_edge_groups[flip]->new_vert;
2596 /* The vert that's in the next loop. */
2597 const uint new_v2 = new_edge->link_edge_groups[1 - flip]->new_vert;
2598 if (k == 0 || face_verts[k - 1] != new_v1) {
2599 face_loops[k] = loopstart + j;
2600 if (fr->reversed) {
2601 face_edges[k] = prior_edge->link_edge_groups[prior_flip]->open_face_edge;
2602 }
2603 else {
2604 face_edges[k] = new_edge->link_edge_groups[flip]->open_face_edge;
2605 }
2606 BLI_assert(k == 0 || edges[face_edges[k]][1] == face_verts[k - 1] ||
2607 edges[face_edges[k]][0] == face_verts[k - 1]);
2608 BLI_assert(face_edges[k] == MOD_SOLIDIFY_EMPTY_TAG ||
2609 edges[face_edges[k]][1] == new_v1 || edges[face_edges[k]][0] == new_v1);
2610 face_verts[k++] = new_v1;
2611 }
2612 prior_edge = new_edge;
2613 prior_flip = 1 - flip;
2614 if (j < totloop - 1 || face_verts[0] != new_v2) {
2615 face_loops[k] = loopstart + (j + 1) % totloop;
2616 face_edges[k] = new_edge->new_edge;
2617 face_verts[k++] = new_v2;
2618 }
2619 else {
2620 face_edges[0] = new_edge->new_edge;
2621 }
2622 }
2623 }
2624 if (k > 2 && valid_edges > 2) {
2626 &mesh->face_data, &result->face_data, int(i / 2), int(face_index), 1);
2627 face_offsets[face_index] = int(loop_index);
2628 dst_material_index.span[face_index] = (!src_material_index.is_empty() ?
2629 src_material_index[fr->index] :
2630 0) +
2631 (fr->reversed != do_flip ? mat_ofs : 0);
2632 CLAMP(dst_material_index.span[face_index], 0, mat_nr_max);
2633 if (fr->reversed != do_flip) {
2634 for (int l = int(k) - 1; l >= 0; l--) {
2635 if (shell_defgrp_index != -1) {
2636 BKE_defvert_ensure_index(&dst_dvert[face_verts[l]], shell_defgrp_index)->weight =
2637 1.0f;
2638 }
2639 CustomData_copy_data(&mesh->corner_data,
2640 &result->corner_data,
2641 int(face_loops[l]),
2642 int(loop_index),
2643 1);
2644 corner_verts[loop_index] = face_verts[l];
2645 corner_edges[loop_index++] = face_edges[l];
2646 }
2647 }
2648 else {
2649 uint l = k - 1;
2650 for (uint next_l = 0; next_l < k; next_l++) {
2651 CustomData_copy_data(&mesh->corner_data,
2652 &result->corner_data,
2653 int(face_loops[l]),
2654 int(loop_index),
2655 1);
2656 corner_verts[loop_index] = face_verts[l];
2657 corner_edges[loop_index++] = face_edges[next_l];
2658 l = next_l;
2659 }
2660 }
2661 face_index++;
2662 }
2663 }
2664 }
2665 MEM_freeN(face_loops);
2666 MEM_freeN(face_verts);
2667 MEM_freeN(face_edges);
2668 }
2669 if (edge_index != new_edges_num) {
2671 md,
2672 "Internal Error: edges array wrong size: %u instead of %u",
2673 new_edges_num,
2674 edge_index);
2675 }
2676 if (face_index != new_faces_num) {
2678 md,
2679 "Internal Error: faces array wrong size: %u instead of %u",
2680 new_faces_num,
2681 face_index);
2682 }
2683 if (loop_index != new_loops_num) {
2685 md,
2686 "Internal Error: loops array wrong size: %u instead of %u",
2687 new_loops_num,
2688 loop_index);
2689 }
2690 BLI_assert(edge_index == new_edges_num);
2691 BLI_assert(face_index == new_faces_num);
2692 BLI_assert(loop_index == new_loops_num);
2693
2694 /* Free remaining memory */
2695 {
2696 MEM_freeN(vm);
2697 MEM_freeN(edge_adj_faces_len);
2698 uint i = 0;
2699 for (EdgeGroup **p = orig_vert_groups_arr; i < verts_num; i++, p++) {
2700 if (*p) {
2701 for (EdgeGroup *eg = *p; eg->valid; eg++) {
2702 MEM_freeN(eg->edges);
2703 }
2704 MEM_freeN(*p);
2705 }
2706 }
2707 MEM_freeN(orig_vert_groups_arr);
2708 i = edges_num;
2709 for (NewEdgeRef ***p = orig_edge_data_arr + (edges_num - 1); i > 0; i--, p--) {
2710 if (*p && (**p)->old_edge == i - 1) {
2711 for (NewEdgeRef **l = *p; *l; l++) {
2712 MEM_freeN(*l);
2713 }
2714 MEM_freeN(*p);
2715 }
2716 }
2717 MEM_freeN(orig_edge_data_arr);
2718 MEM_freeN(orig_edge_lengths);
2719 i = 0;
2720 for (NewFaceRef *p = face_sides_arr; i < faces_num * 2; i++, p++) {
2721 MEM_freeN(p->link_edges);
2722 }
2723 MEM_freeN(face_sides_arr);
2724 }
2725
2726#undef MOD_SOLIDIFY_EMPTY_TAG
2727
2728 dst_material_index.finish();
2729
2730 return result;
2731}
2732
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name, const int totelem)
@ CD_SET_DEFAULT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
#define ORIGINDEX_NONE
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:814
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:543
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:770
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_kdtree_nd_ insert(KDTree *tree, int index, const float co[KD_DIMS]) ATTR_NONNULL(1
MINLINE float max_ff(float a, float b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
#define M_PI
void zero_m3(float m[3][3])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
bool invert_m3(float mat[3][3])
MINLINE void swap_v4_v4(float a[4], float b[4])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
#define CLAMP(a, b, c)
#define UNLIKELY(x)
#define ELEM(...)
#define LIKELY(x)
@ CD_PROP_FLOAT
@ MOD_SOLIDIFY_RIM
@ MOD_SOLIDIFY_FLIP
@ MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP
@ MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES
@ MOD_SOLIDIFY_VGROUP_INV
@ MOD_SOLIDIFY_NOSHELL
@ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_FLAT
@ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_ROUND
@ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_NONE
@ MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN
@ MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS
Object is a sort of wrapper for general info.
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
Read Guarded memory(de)allocation.
Mesh * MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static int comp_float_int_pair(const void *a, const void *b)
static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3], const float ref_n[3], const float axis[3])
static float clamp_nonzero(const float value, const float epsilon)
#define MOD_SOLIDIFY_EMPTY_TAG
static float project_v3_v3(float r[3], const float a[3])
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:159
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
constexpr int64_t size() const
constexpr int64_t start() const
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr bool is_empty() const
Definition BLI_span.hh:261
GAttributeReader lookup(const StringRef attribute_id) const
local_group_size(16, 16) .push_constant(Type b
#define printf
#define cosf(x)
#define acosf(x)
#define fabsf(x)
#define sqrtf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
int count
void *(* MEM_reallocN_id)(void *vmemh, size_t len, const char *str)
Definition mallocn.cc:40
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float cross(const float2 a, const float2 b)
static ulong * next
Frequency::GEOMETRY nor[]
__int64 int64_t
Definition stdint.h:89
NewFaceRef * faces[2]
struct EdgeGroup * link_edge_groups[2]
NewEdgeRef ** link_edges
blender::IndexRange face