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