Blender  V2.93
MOD_solidify_extrude.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_bitmap.h"
24 #include "BLI_math.h"
25 #include "BLI_utildefines_stack.h"
26 
27 #include "DNA_mesh_types.h"
28 #include "DNA_meshdata_types.h"
29 #include "DNA_object_types.h"
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "BKE_deform.h"
34 #include "BKE_mesh.h"
35 #include "BKE_particle.h"
36 
37 #include "MOD_modifiertypes.h"
38 #include "MOD_solidify_util.h" /* own include */
39 #include "MOD_util.h"
40 
41 #ifdef __GNUC__
42 # pragma GCC diagnostic error "-Wsign-conversion"
43 #endif
44 
45 /* -------------------------------------------------------------------- */
49 /* specific function for solidify - define locally */
50 BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
51 {
52  r[0] += (float)a[0] * f;
53  r[1] += (float)a[1] * f;
54  r[2] += (float)a[2] * f;
55 }
56 
59 /* -------------------------------------------------------------------- */
63 /* skip shell thickness for non-manifold edges, see T35710. */
64 #define USE_NONMANIFOLD_WORKAROUND
65 
66 /* *** derived mesh high quality normal calculation function *** */
67 /* could be exposed for other functions to use */
68 
69 typedef struct EdgeFaceRef {
70  int p1; /* init as -1 */
71  int p2;
73 
74 BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
75 {
76  return !((edge_ref->p1 == 0) && (edge_ref->p2 == 0));
77 }
78 
84 static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_vert_nors)[3])
85 {
86  int i, numVerts, numEdges, numPolys;
87  MPoly *mpoly, *mp;
88  MLoop *mloop, *ml;
89  MEdge *medge, *ed;
90  MVert *mvert, *mv;
91 
92  numVerts = mesh->totvert;
93  numEdges = mesh->totedge;
94  numPolys = mesh->totpoly;
95  mpoly = mesh->mpoly;
96  medge = mesh->medge;
97  mvert = mesh->mvert;
98  mloop = mesh->mloop;
99 
100  /* we don't want to overwrite any referenced layers */
101 
102  /* Doesn't work here! */
103 #if 0
104  mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts);
105  cddm->mvert = mv;
106 #endif
107 
108  mv = mvert;
109  mp = mpoly;
110 
111  {
112  EdgeFaceRef *edge_ref_array = MEM_calloc_arrayN(
113  (size_t)numEdges, sizeof(EdgeFaceRef), "Edge Connectivity");
114  EdgeFaceRef *edge_ref;
115  float edge_normal[3];
116 
117  /* Add an edge reference if it's not there, pointing back to the face index. */
118  for (i = 0; i < numPolys; i++, mp++) {
119  int j;
120 
121  ml = mloop + mp->loopstart;
122 
123  for (j = 0; j < mp->totloop; j++, ml++) {
124  /* --- add edge ref to face --- */
125  edge_ref = &edge_ref_array[ml->e];
126  if (!edgeref_is_init(edge_ref)) {
127  edge_ref->p1 = i;
128  edge_ref->p2 = -1;
129  }
130  else if ((edge_ref->p1 != -1) && (edge_ref->p2 == -1)) {
131  edge_ref->p2 = i;
132  }
133  else {
134  /* 3+ faces using an edge, we can't handle this usefully */
135  edge_ref->p1 = edge_ref->p2 = -1;
136 #ifdef USE_NONMANIFOLD_WORKAROUND
137  medge[ml->e].flag |= ME_EDGE_TMP_TAG;
138 #endif
139  }
140  /* --- done --- */
141  }
142  }
143 
144  for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) {
145  /* Get the edge vert indices, and edge value (the face indices that use it) */
146 
147  if (edgeref_is_init(edge_ref) && (edge_ref->p1 != -1)) {
148  if (edge_ref->p2 != -1) {
149  /* We have 2 faces using this edge, calculate the edges normal
150  * using the angle between the 2 faces as a weighting */
151 #if 0
152  add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
154  edge_normal,
155  angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
156 #else
158  edge_normal, poly_nors[edge_ref->p1], poly_nors[edge_ref->p2]);
159 #endif
160  }
161  else {
162  /* only one face attached to that edge */
163  /* an edge without another attached- the weight on this is undefined */
164  copy_v3_v3(edge_normal, poly_nors[edge_ref->p1]);
165  }
166  add_v3_v3(r_vert_nors[ed->v1], edge_normal);
167  add_v3_v3(r_vert_nors[ed->v2], edge_normal);
168  }
169  }
170  MEM_freeN(edge_ref_array);
171  }
172 
173  /* normalize vertex normals and assign */
174  for (i = 0; i < numVerts; i++, mv++) {
175  if (normalize_v3(r_vert_nors[i]) == 0.0f) {
176  normal_short_to_float_v3(r_vert_nors[i], mv->no);
177  }
178  }
179 }
180 
183 /* -------------------------------------------------------------------- */
186 /* NOLINTNEXTLINE: readability-function-size */
188 {
189  Mesh *result;
190  const SolidifyModifierData *smd = (SolidifyModifierData *)md;
191 
192  MVert *mv, *mvert, *orig_mvert;
193  MEdge *ed, *medge, *orig_medge;
194  MLoop *ml, *mloop, *orig_mloop;
195  MPoly *mp, *mpoly, *orig_mpoly;
196  const uint numVerts = (uint)mesh->totvert;
197  const uint numEdges = (uint)mesh->totedge;
198  const uint numPolys = (uint)mesh->totpoly;
199  const uint numLoops = (uint)mesh->totloop;
200  uint newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
201 
202  /* only use material offsets if we have 2 or more materials */
203  const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0;
204  const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0;
205  const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0;
206 
207  /* use for edges */
208  /* over-alloc new_vert_arr, old_vert_arr */
209  uint *new_vert_arr = NULL;
210  STACK_DECLARE(new_vert_arr);
211 
212  uint *new_edge_arr = NULL;
213  STACK_DECLARE(new_edge_arr);
214 
215  uint *old_vert_arr = MEM_calloc_arrayN(
216  numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify");
217 
218  uint *edge_users = NULL;
219  int *edge_order = NULL;
220 
221  float(*vert_nors)[3] = NULL;
222  float(*poly_nors)[3] = NULL;
223 
224  const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) ||
225  (smd->flag & MOD_SOLIDIFY_EVEN) ||
227  (smd->bevel_convex != 0);
228 
229  const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
230  const float ofs_new = smd->offset + ofs_orig;
231  const float offset_fac_vg = smd->offset_fac_vg;
232  const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
233  const float bevel_convex = smd->bevel_convex;
234  const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
235  const bool do_clamp = (smd->offset_clamp != 0.0f);
236  const bool do_angle_clamp = do_clamp && (smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP) != 0;
237  const bool do_bevel_convex = bevel_convex != 0.0f;
238  const bool do_rim = (smd->flag & MOD_SOLIDIFY_RIM) != 0;
239  const bool do_shell = !(do_rim && (smd->flag & MOD_SOLIDIFY_NOSHELL) != 0);
240 
241  /* weights */
242  MDeformVert *dvert;
243  const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
244  int defgrp_index;
245  const int shell_defgrp_index = BKE_object_defgroup_name_index(ctx->object,
246  smd->shell_defgrp_name);
247  const int rim_defgrp_index = BKE_object_defgroup_name_index(ctx->object, smd->rim_defgrp_name);
248 
249  /* array size is doubled in case of using a shell */
250  const uint stride = do_shell ? 2 : 1;
251 
252  MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
253 
254  orig_mvert = mesh->mvert;
255  orig_medge = mesh->medge;
256  orig_mloop = mesh->mloop;
257  orig_mpoly = mesh->mpoly;
258 
259  if (need_poly_normals) {
260  /* calculate only face normals */
261  poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
262  BKE_mesh_calc_normals_poly(orig_mvert,
263  NULL,
264  (int)numVerts,
265  orig_mloop,
266  orig_mpoly,
267  (int)numLoops,
268  (int)numPolys,
269  poly_nors,
270  true);
271  }
272 
273  STACK_INIT(new_vert_arr, numVerts * 2);
274  STACK_INIT(new_edge_arr, numEdges * 2);
275 
276  if (do_rim) {
277  BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
278  uint eidx;
279  uint i;
280 
281 #define INVALID_UNUSED ((uint)-1)
282 #define INVALID_PAIR ((uint)-2)
283 
284  new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__);
285  new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__);
286 
287  edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges");
288  edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod order");
289 
290  /* save doing 2 loops here... */
291 #if 0
292  copy_vn_i(edge_users, numEdges, INVALID_UNUSED);
293 #endif
294 
295  for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
296  edge_users[eidx] = INVALID_UNUSED;
297  }
298 
299  for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) {
300  MLoop *ml_prev;
301  int j;
302 
303  ml = orig_mloop + mp->loopstart;
304  ml_prev = ml + (mp->totloop - 1);
305 
306  for (j = 0; j < mp->totloop; j++, ml++) {
307  /* add edge user */
308  eidx = ml_prev->e;
309  if (edge_users[eidx] == INVALID_UNUSED) {
310  ed = orig_medge + eidx;
311  BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
312  edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numPolys);
313  edge_order[eidx] = j;
314  }
315  else {
316  edge_users[eidx] = INVALID_PAIR;
317  }
318  ml_prev = ml;
319  }
320  }
321 
322  for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
323  if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) {
324  BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1);
325  BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2);
326  STACK_PUSH(new_edge_arr, eidx);
327  newPolys++;
328  newLoops += 4;
329  }
330  }
331 
332  for (i = 0; i < numVerts; i++) {
333  if (BLI_BITMAP_TEST(orig_mvert_tag, i)) {
334  old_vert_arr[i] = STACK_SIZE(new_vert_arr);
335  STACK_PUSH(new_vert_arr, i);
336  rimVerts++;
337  }
338  else {
339  old_vert_arr[i] = INVALID_UNUSED;
340  }
341  }
342 
343  MEM_freeN(orig_mvert_tag);
344  }
345 
346  if (do_shell == false) {
347  /* only add rim vertices */
348  newVerts = rimVerts;
349  /* each extruded face needs an opposite edge */
350  newEdges = newPolys;
351  }
352  else {
353  /* (stride == 2) in this case, so no need to add newVerts/newEdges */
354  BLI_assert(newVerts == 0);
355  BLI_assert(newEdges == 0);
356  }
357 
358  if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
359  vert_nors = MEM_calloc_arrayN(numVerts, sizeof(float[3]), "mod_solid_vno_hq");
360  mesh_calc_hq_normal(mesh, poly_nors, vert_nors);
361  }
362 
364  (int)((numVerts * stride) + newVerts),
365  (int)((numEdges * stride) + newEdges + rimVerts),
366  0,
367  (int)((numLoops * stride) + newLoops),
368  (int)((numPolys * stride) + newPolys));
369 
370  mpoly = result->mpoly;
371  mloop = result->mloop;
372  medge = result->medge;
373  mvert = result->mvert;
374 
375  if (do_bevel_convex) {
376  /* Make sure bweight is enabled. */
377  result->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
378  }
379 
380  if (do_shell) {
381  CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts);
382  CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)numVerts, (int)numVerts);
383 
384  CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges);
385  CustomData_copy_data(&mesh->edata, &result->edata, 0, (int)numEdges, (int)numEdges);
386 
387  CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops);
388  /* DO NOT copy here the 'copied' part of loop data, we want to reverse loops
389  * (so that winding of copied face get reversed, so that normals get reversed
390  * and point in expected direction...).
391  * If we also copy data here, then this data get overwritten
392  * (and allocated memory becomes memleak). */
393 
394  CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys);
395  CustomData_copy_data(&mesh->pdata, &result->pdata, 0, (int)numPolys, (int)numPolys);
396  }
397  else {
398  int i, j;
399  CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts);
400  for (i = 0, j = (int)numVerts; i < numVerts; i++) {
401  if (old_vert_arr[i] != INVALID_UNUSED) {
402  CustomData_copy_data(&mesh->vdata, &result->vdata, i, j, 1);
403  j++;
404  }
405  }
406 
407  CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges);
408 
409  for (i = 0, j = (int)numEdges; i < numEdges; i++) {
410  if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) {
411  MEdge *ed_src, *ed_dst;
412  CustomData_copy_data(&mesh->edata, &result->edata, i, j, 1);
413 
414  ed_src = &medge[i];
415  ed_dst = &medge[j];
416  ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts;
417  ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts;
418  j++;
419  }
420  }
421 
422  /* will be created later */
423  CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops);
424  CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys);
425  }
426 
427  /* initializes: (i_end, do_shell_align, mv) */
428 #define INIT_VERT_ARRAY_OFFSETS(test) \
429  if (((ofs_new >= ofs_orig) == do_flip) == test) { \
430  i_end = numVerts; \
431  do_shell_align = true; \
432  mv = mvert; \
433  } \
434  else { \
435  if (do_shell) { \
436  i_end = numVerts; \
437  do_shell_align = true; \
438  } \
439  else { \
440  i_end = newVerts; \
441  do_shell_align = false; \
442  } \
443  mv = &mvert[numVerts]; \
444  } \
445  (void)0
446 
447  /* flip normals */
448 
449  if (do_shell) {
450  uint i;
451 
452  mp = mpoly + numPolys;
453  for (i = 0; i < mesh->totpoly; i++, mp++) {
454  const int loop_end = mp->totloop - 1;
455  MLoop *ml2;
456  uint e;
457  int j;
458 
459  /* reverses the loop direction (MLoop.v as well as custom-data)
460  * MLoop.e also needs to be corrected too, done in a separate loop below. */
461  ml2 = mloop + mp->loopstart + mesh->totloop;
462 #if 0
463  for (j = 0; j < mp->totloop; j++) {
465  &result->ldata,
466  mp->loopstart + j,
467  mp->loopstart + (loop_end - j) + mesh->totloop,
468  1);
469  }
470 #else
471  /* slightly more involved, keep the first vertex the same for the copy,
472  * ensures the diagonals in the new face match the original. */
473  j = 0;
474  for (int j_prev = loop_end; j < mp->totloop; j_prev = j++) {
476  &result->ldata,
477  mp->loopstart + j,
478  mp->loopstart + (loop_end - j_prev) + mesh->totloop,
479  1);
480  }
481 #endif
482 
483  if (mat_ofs) {
484  mp->mat_nr += mat_ofs;
485  CLAMP(mp->mat_nr, 0, mat_nr_max);
486  }
487 
488  e = ml2[0].e;
489  for (j = 0; j < loop_end; j++) {
490  ml2[j].e = ml2[j + 1].e;
491  }
492  ml2[loop_end].e = e;
493 
494  mp->loopstart += mesh->totloop;
495 
496  for (j = 0; j < mp->totloop; j++) {
497  ml2[j].e += numEdges;
498  ml2[j].v += numVerts;
499  }
500  }
501 
502  for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) {
503  ed->v1 += numVerts;
504  ed->v2 += numVerts;
505  }
506  }
507 
508  /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */
509  if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
510  /* no even thickness, very simple */
511  float scalar_short;
512  float scalar_short_vgroup;
513 
514  /* for clamping */
515  float *vert_lens = NULL;
516  float *vert_angs = NULL;
517  const float offset = fabsf(smd->offset) * smd->offset_clamp;
518  const float offset_sq = offset * offset;
519 
520  /* for bevel weight */
521  float *edge_angs = NULL;
522 
523  if (do_clamp) {
524  vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
525  copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
526  for (uint i = 0; i < numEdges; i++) {
527  const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
528  vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq);
529  vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq);
530  }
531  }
532 
533  if (do_angle_clamp || do_bevel_convex) {
534  uint eidx;
535  if (do_angle_clamp) {
536  vert_angs = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_angs");
537  copy_vn_fl(vert_angs, (int)numVerts, 0.5f * M_PI);
538  }
539  if (do_bevel_convex) {
540  edge_angs = MEM_malloc_arrayN(numEdges, sizeof(float), "edge_angs");
541  if (!do_rim) {
542  edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges");
543  }
544  }
545  uint(*edge_user_pairs)[2] = MEM_malloc_arrayN(
546  numEdges, sizeof(*edge_user_pairs), "edge_user_pairs");
547  for (eidx = 0; eidx < numEdges; eidx++) {
548  edge_user_pairs[eidx][0] = INVALID_UNUSED;
549  edge_user_pairs[eidx][1] = INVALID_UNUSED;
550  }
551  mp = orig_mpoly;
552  for (uint i = 0; i < numPolys; i++, mp++) {
553  ml = orig_mloop + mp->loopstart;
554  MLoop *ml_prev = ml + (mp->totloop - 1);
555 
556  for (uint j = 0; j < mp->totloop; j++, ml++) {
557  /* add edge user */
558  eidx = ml_prev->e;
559  ed = orig_medge + eidx;
560  BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
561  char flip = (char)((ml_prev->v > ml->v) == (ed->v1 < ed->v2));
562  if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
563  edge_user_pairs[eidx][flip] = i;
564  }
565  else {
566  edge_user_pairs[eidx][0] = INVALID_PAIR;
567  edge_user_pairs[eidx][1] = INVALID_PAIR;
568  }
569  ml_prev = ml;
570  }
571  }
572  ed = orig_medge;
573  float e[3];
574  for (uint i = 0; i < numEdges; i++, ed++) {
575  if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
576  !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) {
577  const float *n0 = poly_nors[edge_user_pairs[i][0]];
578  const float *n1 = poly_nors[edge_user_pairs[i][1]];
579  sub_v3_v3v3(e, orig_mvert[ed->v1].co, orig_mvert[ed->v2].co);
580  normalize_v3(e);
581  const float angle = angle_signed_on_axis_v3v3_v3(n0, n1, e);
582  if (do_angle_clamp) {
583  vert_angs[ed->v1] = max_ff(vert_angs[ed->v1], angle);
584  vert_angs[ed->v2] = max_ff(vert_angs[ed->v2], angle);
585  }
586  if (do_bevel_convex) {
587  edge_angs[i] = angle;
588  if (!do_rim) {
589  edge_users[i] = INVALID_PAIR;
590  }
591  }
592  }
593  }
594  MEM_freeN(edge_user_pairs);
595  }
596 
597  if (ofs_new != 0.0f) {
598  uint i_orig, i_end;
599  bool do_shell_align;
600 
601  scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
602 
604 
605  for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
606  const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
607  if (dvert) {
608  MDeformVert *dv = &dvert[i];
609  if (defgrp_invert) {
610  scalar_short_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
611  }
612  else {
613  scalar_short_vgroup = BKE_defvert_find_weight(dv, defgrp_index);
614  }
615  scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) *
616  scalar_short;
617  }
618  if (do_clamp && offset > FLT_EPSILON) {
619  /* always reset because we may have set before */
620  if (dvert == NULL) {
621  scalar_short_vgroup = scalar_short;
622  }
623  if (do_angle_clamp) {
624  float cos_ang = cosf(((2 * M_PI) - vert_angs[i]) * 0.5f);
625  if (cos_ang > 0) {
626  float max_off = sqrtf(vert_lens[i]) * 0.5f / cos_ang;
627  if (max_off < offset * 0.5f) {
628  scalar_short_vgroup *= max_off / offset * 2;
629  }
630  }
631  }
632  else {
633  if (vert_lens[i] < offset_sq) {
634  float scalar = sqrtf(vert_lens[i]) / offset;
635  scalar_short_vgroup *= scalar;
636  }
637  }
638  }
639  madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
640  }
641  }
642 
643  if (ofs_orig != 0.0f) {
644  uint i_orig, i_end;
645  bool do_shell_align;
646 
647  scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
648 
649  /* as above but swapped */
651 
652  for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
653  const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
654  if (dvert) {
655  MDeformVert *dv = &dvert[i];
656  if (defgrp_invert) {
657  scalar_short_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
658  }
659  else {
660  scalar_short_vgroup = BKE_defvert_find_weight(dv, defgrp_index);
661  }
662  scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) *
663  scalar_short;
664  }
665  if (do_clamp && offset > FLT_EPSILON) {
666  /* always reset because we may have set before */
667  if (dvert == NULL) {
668  scalar_short_vgroup = scalar_short;
669  }
670  if (do_angle_clamp) {
671  float cos_ang = cosf(vert_angs[i_orig] * 0.5f);
672  if (cos_ang > 0) {
673  float max_off = sqrtf(vert_lens[i]) * 0.5f / cos_ang;
674  if (max_off < offset * 0.5f) {
675  scalar_short_vgroup *= max_off / offset * 2;
676  }
677  }
678  }
679  else {
680  if (vert_lens[i] < offset_sq) {
681  float scalar = sqrtf(vert_lens[i]) / offset;
682  scalar_short_vgroup *= scalar;
683  }
684  }
685  }
686  madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
687  }
688  }
689 
690  if (do_bevel_convex) {
691  for (uint i = 0; i < numEdges; i++) {
692  if (edge_users[i] == INVALID_PAIR) {
693  float angle = edge_angs[i];
694  medge[i].bweight = (char)clamp_i(
695  (int)medge[i].bweight + (int)((angle < M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
696  clamp_f(bevel_convex, -1.0f, 0.0f)) *
697  255),
698  0,
699  255);
700  if (do_shell) {
701  medge[i + numEdges].bweight = (char)clamp_i(
702  (int)medge[i + numEdges].bweight +
703  (int)((angle > M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
704  clamp_f(bevel_convex, -1.0f, 0.0f)) *
705  255),
706  0,
707  255);
708  }
709  }
710  }
711  if (!do_rim) {
712  MEM_freeN(edge_users);
713  }
714  MEM_freeN(edge_angs);
715  }
716 
717  if (do_clamp) {
718  MEM_freeN(vert_lens);
719  if (do_angle_clamp) {
720  MEM_freeN(vert_angs);
721  }
722  }
723  }
724  else {
725 #ifdef USE_NONMANIFOLD_WORKAROUND
726  const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0;
727 #endif
728  /* same as EM_solidify() in editmesh_lib.c */
729  float *vert_angles = MEM_calloc_arrayN(
730  numVerts, sizeof(float[2]), "mod_solid_pair"); /* 2 in 1 */
731  float *vert_accum = vert_angles + numVerts;
732  uint vidx;
733  uint i;
734 
735  if (vert_nors == NULL) {
736  vert_nors = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "mod_solid_vno");
737  for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
738  normal_short_to_float_v3(vert_nors[i], mv->no);
739  }
740  }
741 
742  for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
743  /* #BKE_mesh_calc_poly_angles logic is inlined here */
744  float nor_prev[3];
745  float nor_next[3];
746 
747  int i_curr = mp->totloop - 1;
748  int i_next = 0;
749 
750  ml = &mloop[mp->loopstart];
751 
752  sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co);
753  normalize_v3(nor_prev);
754 
755  while (i_next < mp->totloop) {
756  float angle;
757  sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co);
758  normalize_v3(nor_next);
759  angle = angle_normalized_v3v3(nor_prev, nor_next);
760 
761  /* --- not related to angle calc --- */
762  if (angle < FLT_EPSILON) {
763  angle = FLT_EPSILON;
764  }
765 
766  vidx = ml[i_curr].v;
767  vert_accum[vidx] += angle;
768 
769 #ifdef USE_NONMANIFOLD_WORKAROUND
770  /* skip 3+ face user edges */
771  if ((check_non_manifold == false) ||
772  LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) &&
773  ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) {
774  vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) *
775  angle;
776  }
777  else {
778  vert_angles[vidx] += angle;
779  }
780 #else
781  vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle;
782 #endif
783  /* --- end non-angle-calc section --- */
784 
785  /* step */
786  copy_v3_v3(nor_prev, nor_next);
787  i_curr = i_next;
788  i_next++;
789  }
790  }
791 
792  /* vertex group support */
793  if (dvert) {
794  MDeformVert *dv = dvert;
795  float scalar;
796 
797  if (defgrp_invert) {
798  for (i = 0; i < numVerts; i++, dv++) {
799  scalar = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
800  scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
801  vert_angles[i] *= scalar;
802  }
803  }
804  else {
805  for (i = 0; i < numVerts; i++, dv++) {
806  scalar = BKE_defvert_find_weight(dv, defgrp_index);
807  scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
808  vert_angles[i] *= scalar;
809  }
810  }
811  }
812 
813  /* for angle clamp */
814  float *vert_angs = NULL;
815  /* for bevel convex */
816  float *edge_angs = NULL;
817 
818  if (do_angle_clamp || do_bevel_convex) {
819  uint eidx;
820  if (do_angle_clamp) {
821  vert_angs = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_angs even");
822  copy_vn_fl(vert_angs, (int)numVerts, 0.5f * M_PI);
823  }
824  if (do_bevel_convex) {
825  edge_angs = MEM_malloc_arrayN(numEdges, sizeof(float), "edge_angs even");
826  if (!do_rim) {
827  edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges");
828  }
829  }
830  uint(*edge_user_pairs)[2] = MEM_malloc_arrayN(
831  numEdges, sizeof(*edge_user_pairs), "edge_user_pairs");
832  for (eidx = 0; eidx < numEdges; eidx++) {
833  edge_user_pairs[eidx][0] = INVALID_UNUSED;
834  edge_user_pairs[eidx][1] = INVALID_UNUSED;
835  }
836  for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) {
837  ml = orig_mloop + mp->loopstart;
838  MLoop *ml_prev = ml + (mp->totloop - 1);
839 
840  for (int j = 0; j < mp->totloop; j++, ml++) {
841  /* add edge user */
842  eidx = ml_prev->e;
843  ed = orig_medge + eidx;
844  BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
845  char flip = (char)((ml_prev->v > ml->v) == (ed->v1 < ed->v2));
846  if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
847  edge_user_pairs[eidx][flip] = i;
848  }
849  else {
850  edge_user_pairs[eidx][0] = INVALID_PAIR;
851  edge_user_pairs[eidx][1] = INVALID_PAIR;
852  }
853  ml_prev = ml;
854  }
855  }
856  ed = orig_medge;
857  float e[3];
858  for (i = 0; i < numEdges; i++, ed++) {
859  if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
860  !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) {
861  const float *n0 = poly_nors[edge_user_pairs[i][0]];
862  const float *n1 = poly_nors[edge_user_pairs[i][1]];
863  if (do_angle_clamp) {
864  const float angle = M_PI - angle_normalized_v3v3(n0, n1);
865  vert_angs[ed->v1] = max_ff(vert_angs[ed->v1], angle);
866  vert_angs[ed->v2] = max_ff(vert_angs[ed->v2], angle);
867  }
868  if (do_bevel_convex) {
869  sub_v3_v3v3(e, orig_mvert[ed->v1].co, orig_mvert[ed->v2].co);
870  normalize_v3(e);
871  edge_angs[i] = angle_signed_on_axis_v3v3_v3(n0, n1, e);
872  if (!do_rim) {
873  edge_users[i] = INVALID_PAIR;
874  }
875  }
876  }
877  }
878  MEM_freeN(edge_user_pairs);
879  }
880 
881  if (do_clamp) {
882  const float clamp_fac = 1 + (do_angle_clamp ? fabsf(smd->offset_fac) : 0);
883  const float offset = fabsf(smd->offset) * smd->offset_clamp * clamp_fac;
884  if (offset > FLT_EPSILON) {
885  float *vert_lens_sq = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens_sq");
886  const float offset_sq = offset * offset;
887  copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
888  for (i = 0; i < numEdges; i++) {
889  const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
890  vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len);
891  vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len);
892  }
893  if (do_angle_clamp) {
894  for (i = 0; i < numVerts; i++) {
895  float cos_ang = cosf(vert_angs[i] * 0.5f);
896  if (cos_ang > 0) {
897  float max_off = sqrtf(vert_lens_sq[i]) * 0.5f / cos_ang;
898  if (max_off < offset * 0.5f) {
899  vert_angles[i] *= max_off / offset * 2;
900  }
901  }
902  }
903  MEM_freeN(vert_angs);
904  }
905  else {
906  for (i = 0; i < numVerts; i++) {
907  if (vert_lens_sq[i] < offset_sq) {
908  float scalar = sqrtf(vert_lens_sq[i]) / offset;
909  vert_angles[i] *= scalar;
910  }
911  }
912  }
913  MEM_freeN(vert_lens_sq);
914  }
915  }
916 
917  if (do_bevel_convex) {
918  for (i = 0; i < numEdges; i++) {
919  if (edge_users[i] == INVALID_PAIR) {
920  float angle = edge_angs[i];
921  medge[i].bweight = (char)clamp_i(
922  (int)medge[i].bweight + (int)((angle < M_PI ? clamp_f(bevel_convex, 0, 1) :
923  clamp_f(bevel_convex, -1, 0)) *
924  255),
925  0,
926  255);
927  if (do_shell) {
928  medge[i + numEdges].bweight = (char)clamp_i(
929  (int)medge[i + numEdges].bweight +
930  (int)((angle > M_PI ? clamp_f(bevel_convex, 0, 1) :
931  clamp_f(bevel_convex, -1, 0)) *
932  255),
933  0,
934  255);
935  }
936  }
937  }
938  if (!do_rim) {
939  MEM_freeN(edge_users);
940  }
941  MEM_freeN(edge_angs);
942  }
943 
944 #undef INVALID_UNUSED
945 #undef INVALID_PAIR
946 
947  if (ofs_new != 0.0f) {
948  uint i_orig, i_end;
949  bool do_shell_align;
950 
952 
953  for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
954  const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
955  if (vert_accum[i_other]) { /* zero if unselected */
956  madd_v3_v3fl(
957  mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
958  }
959  }
960  }
961 
962  if (ofs_orig != 0.0f) {
963  uint i_orig, i_end;
964  bool do_shell_align;
965 
966  /* same as above but swapped, intentional use of 'ofs_new' */
968 
969  for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
970  const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
971  if (vert_accum[i_other]) { /* zero if unselected */
972  madd_v3_v3fl(
973  mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
974  }
975  }
976  }
977 
978  MEM_freeN(vert_angles);
979  }
980 
981  if (vert_nors) {
982  MEM_freeN(vert_nors);
983  }
984 
985  /* must recalculate normals with vgroups since they can displace unevenly T26888. */
986  if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || do_rim || dvert) {
987  result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
988  }
989  else if (do_shell) {
990  uint i;
991  /* flip vertex normals for copied verts */
992  mv = mvert + numVerts;
993  for (i = 0; i < numVerts; i++, mv++) {
994  negate_v3_short(mv->no);
995  }
996  }
997 
998  /* Add vertex weights for rim and shell vgroups. */
999  if (shell_defgrp_index != -1 || rim_defgrp_index != -1) {
1001  /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
1002  if (dvert == NULL) {
1003  /* Add a valid data layer! */
1004  dvert = CustomData_add_layer(
1005  &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, result->totvert);
1006  }
1007  /* Ultimate security check. */
1008  if (dvert != NULL) {
1009  result->dvert = dvert;
1010 
1011  if (rim_defgrp_index != -1) {
1012  for (uint i = 0; i < rimVerts; i++) {
1013  BKE_defvert_ensure_index(&result->dvert[new_vert_arr[i]], rim_defgrp_index)->weight =
1014  1.0f;
1015  BKE_defvert_ensure_index(&result->dvert[(do_shell ? new_vert_arr[i] : i) + numVerts],
1016  rim_defgrp_index)
1017  ->weight = 1.0f;
1018  }
1019  }
1020 
1021  if (shell_defgrp_index != -1) {
1022  for (uint i = numVerts; i < result->totvert; i++) {
1023  BKE_defvert_ensure_index(&result->dvert[i], shell_defgrp_index)->weight = 1.0f;
1024  }
1025  }
1026  }
1027  }
1028  if (do_rim) {
1029  uint i;
1030 
1031  /* bugger, need to re-calculate the normals for the new edge faces.
1032  * This could be done in many ways, but probably the quickest way
1033  * is to calculate the average normals for side faces only.
1034  * Then blend them with the normals of the edge verts.
1035  *
1036  * at the moment its easiest to allocate an entire array for every vertex,
1037  * even though we only need edge verts - campbell
1038  */
1039 
1040 #define SOLIDIFY_SIDE_NORMALS
1041 
1042 #ifdef SOLIDIFY_SIDE_NORMALS
1043  /* Note that, due to the code setting cd_dirty_vert a few lines above,
1044  * do_side_normals is always false. - Sybren */
1045  const bool do_side_normals = !(result->runtime.cd_dirty_vert & CD_MASK_NORMAL);
1046  /* annoying to allocate these since we only need the edge verts, */
1047  float(*edge_vert_nos)[3] = do_side_normals ?
1048  MEM_calloc_arrayN(numVerts, sizeof(float[3]), __func__) :
1049  NULL;
1050  float nor[3];
1051 #endif
1052  const uchar crease_rim = smd->crease_rim * 255.0f;
1053  const uchar crease_outer = smd->crease_outer * 255.0f;
1054  const uchar crease_inner = smd->crease_inner * 255.0f;
1055 
1056  int *origindex_edge;
1057  int *orig_ed;
1058  uint j;
1059 
1060  if (crease_rim || crease_outer || crease_inner) {
1061  result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
1062  }
1063 
1064  /* add faces & edges */
1065  origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
1066  orig_ed = (origindex_edge) ? &origindex_edge[(numEdges * stride) + newEdges] : NULL;
1067  ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */
1068  for (i = 0; i < rimVerts; i++, ed++) {
1069  ed->v1 = new_vert_arr[i];
1070  ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts;
1071  ed->flag |= ME_EDGEDRAW | ME_EDGERENDER;
1072 
1073  if (orig_ed) {
1074  *orig_ed = ORIGINDEX_NONE;
1075  orig_ed++;
1076  }
1077 
1078  if (crease_rim) {
1079  ed->crease = crease_rim;
1080  }
1081  }
1082 
1083  /* faces */
1084  mp = mpoly + (numPolys * stride);
1085  ml = mloop + (numLoops * stride);
1086  j = 0;
1087  for (i = 0; i < newPolys; i++, mp++) {
1088  uint eidx = new_edge_arr[i];
1089  uint pidx = edge_users[eidx];
1090  int k1, k2;
1091  bool flip;
1092 
1093  if (pidx >= numPolys) {
1094  pidx -= numPolys;
1095  flip = true;
1096  }
1097  else {
1098  flip = false;
1099  }
1100 
1101  ed = medge + eidx;
1102 
1103  /* copy most of the face settings */
1105  &mesh->pdata, &result->pdata, (int)pidx, (int)((numPolys * stride) + i), 1);
1106  mp->loopstart = (int)(j + (numLoops * stride));
1107  mp->flag = mpoly[pidx].flag;
1108 
1109  /* notice we use 'mp->totloop' which is later overwritten,
1110  * we could lookup the original face but there's no point since this is a copy
1111  * and will have the same value, just take care when changing order of assignment */
1112 
1113  /* prev loop */
1114  k1 = mpoly[pidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop);
1115 
1116  k2 = mpoly[pidx].loopstart + (edge_order[eidx]);
1117 
1118  mp->totloop = 4;
1119 
1121  &mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 0), 1);
1123  &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 1), 1);
1125  &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 2), 1);
1127  &mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 3), 1);
1128 
1129  if (flip == false) {
1130  ml[j].v = ed->v1;
1131  ml[j++].e = eidx;
1132 
1133  ml[j].v = ed->v2;
1134  ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;
1135 
1136  ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
1137  ml[j++].e = (do_shell ? eidx : i) + numEdges;
1138 
1139  ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
1140  ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;
1141  }
1142  else {
1143  ml[j].v = ed->v2;
1144  ml[j++].e = eidx;
1145 
1146  ml[j].v = ed->v1;
1147  ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;
1148 
1149  ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
1150  ml[j++].e = (do_shell ? eidx : i) + numEdges;
1151 
1152  ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
1153  ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;
1154  }
1155 
1156  if (origindex_edge) {
1157  origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE;
1158  origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE;
1159  }
1160 
1161  /* use the next material index if option enabled */
1162  if (mat_ofs_rim) {
1163  mp->mat_nr += mat_ofs_rim;
1164  CLAMP(mp->mat_nr, 0, mat_nr_max);
1165  }
1166  if (crease_outer) {
1167  /* crease += crease_outer; without wrapping */
1168  char *cr = &(ed->crease);
1169  int tcr = *cr + crease_outer;
1170  *cr = tcr > 255 ? 255 : tcr;
1171  }
1172 
1173  if (crease_inner) {
1174  /* crease += crease_inner; without wrapping */
1175  char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease);
1176  int tcr = *cr + crease_inner;
1177  *cr = tcr > 255 ? 255 : tcr;
1178  }
1179 
1180 #ifdef SOLIDIFY_SIDE_NORMALS
1181  if (do_side_normals) {
1183  mvert[ml[j - 4].v].co,
1184  mvert[ml[j - 3].v].co,
1185  mvert[ml[j - 2].v].co,
1186  mvert[ml[j - 1].v].co);
1187 
1188  add_v3_v3(edge_vert_nos[ed->v1], nor);
1189  add_v3_v3(edge_vert_nos[ed->v2], nor);
1190  }
1191 #endif
1192  }
1193 
1194 #ifdef SOLIDIFY_SIDE_NORMALS
1195  if (do_side_normals) {
1196  const MEdge *ed_orig = medge;
1197  ed = medge + (numEdges * stride);
1198  for (i = 0; i < rimVerts; i++, ed++, ed_orig++) {
1199  float nor_cpy[3];
1200  short *nor_short;
1201  int k;
1202 
1203  /* note, only the first vertex (lower half of the index) is calculated */
1204  BLI_assert(ed->v1 < numVerts);
1205  normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->v1]);
1206 
1207  for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
1208  nor_short = mvert[*(&ed->v1 + k)].no;
1209  normal_short_to_float_v3(nor, nor_short);
1210  add_v3_v3(nor, nor_cpy);
1211  normalize_v3(nor);
1212  normal_float_to_short_v3(nor_short, nor);
1213  }
1214  }
1215 
1216  MEM_freeN(edge_vert_nos);
1217  }
1218 #endif
1219 
1220  MEM_freeN(new_vert_arr);
1221  MEM_freeN(new_edge_arr);
1222 
1223  MEM_freeN(edge_users);
1224  MEM_freeN(edge_order);
1225  }
1226 
1227  if (old_vert_arr) {
1228  MEM_freeN(old_vert_arr);
1229  }
1230 
1231  if (poly_nors) {
1232  MEM_freeN(poly_nors);
1233  }
1234 
1235  return result;
1236 }
1237 
1238 #undef SOLIDIFY_SIDE_NORMALS
1239 
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)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:63
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:78
#define BLI_BITMAP_NEW(_tot, _alloc_string)
Definition: BLI_bitmap.h:50
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:32
#define BLI_INLINE
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 int clamp_i(int value, int min, int max)
#define M_PI
Definition: BLI_math_base.h:38
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition: math_geom.c:68
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
void copy_vn_fl(float *array_tar, const int size, const float val)
Definition: math_vector.c:1410
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
void copy_vn_i(int *array_tar, const int size, const int val)
Definition: math_vector.c:1374
MINLINE void normal_float_to_short_v3(short r[3], const float n[3])
MINLINE float normalize_v3(float r[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void normal_short_to_float_v3(float r[3], const short n[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:326
float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:551
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_short(short r[3])
MINLINE float normalize_v3_length(float r[3], const float unit_scale)
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:505
MINLINE void add_v3_v3(float r[3], const float a[3])
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
#define ELEM(...)
#define LIKELY(x)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_INIT(stack, tot)
#define STACK_SIZE(stack)
#define CD_MASK_NORMAL
@ CD_MDEFORMVERT
@ CD_ORIGINDEX
@ CD_MVERT
@ ME_CDFLAG_EDGE_CREASE
@ ME_CDFLAG_EDGE_BWEIGHT
@ ME_EDGEDRAW
@ ME_EDGERENDER
@ ME_EDGE_TMP_TAG
@ MOD_SOLIDIFY_RIM
@ MOD_SOLIDIFY_FLIP
@ MOD_SOLIDIFY_NORMAL_CALC
@ MOD_SOLIDIFY_EVEN
@ MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP
@ MOD_SOLIDIFY_VGROUP_INV
@ MOD_SOLIDIFY_NOSHELL
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 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 stride
_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.
static void mesh_calc_hq_normal(Mesh *mesh, float(*poly_nors)[3], float(*r_vert_nors)[3])
BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
#define INVALID_UNUSED
struct EdgeFaceRef EdgeFaceRef
BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
#define INVALID_PAIR
Mesh * MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
#define INIT_VERT_ARRAY_OFFSETS(test)
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 BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
uint nor
#define cosf(x)
#define fabsf(x)
#define sqrtf(x)
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
static unsigned a[3]
Definition: RandGen.cpp:92
unsigned int v1
unsigned int v2
unsigned int e
unsigned int v
short mat_nr
float co[3]
int64_t cd_dirty_vert
struct MEdge * medge
struct CustomData pdata ldata
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
Mesh_Runtime runtime
int totpoly
int totloop
struct MPoly * mpoly
struct Object * object
Definition: BKE_modifier.h:154