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