Blender  V3.3
MOD_weighted_normal.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "MEM_guardedalloc.h"
8 
9 #include "BLI_bitmap.h"
10 #include "BLI_linklist.h"
11 #include "BLI_math.h"
12 
13 #include "BLT_translation.h"
14 
15 #include "DNA_defaults.h"
16 #include "DNA_mesh_types.h"
17 #include "DNA_meshdata_types.h"
18 #include "DNA_object_types.h"
19 #include "DNA_scene_types.h"
20 #include "DNA_screen_types.h"
21 
22 #include "BKE_context.h"
23 #include "BKE_deform.h"
24 #include "BKE_lib_id.h"
25 #include "BKE_mesh.h"
26 #include "BKE_screen.h"
27 
28 #include "UI_interface.h"
29 #include "UI_resources.h"
30 
31 #include "RNA_access.h"
32 #include "RNA_prototypes.h"
33 
34 #include "MOD_modifiertypes.h"
35 #include "MOD_ui_common.h"
36 #include "MOD_util.h"
37 
38 #include "bmesh.h"
39 
40 #define CLNORS_VALID_VEC_LEN (1e-6f)
41 
42 typedef struct ModePair {
43  float val; /* Contains mode based value (face area / corner angle). */
44  int index; /* Index value per poly or per loop. */
46 
47 /* Sorting function used in modifier, sorts in decreasing order. */
48 static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
49 {
50  ModePair *r1 = (ModePair *)p1;
51  ModePair *r2 = (ModePair *)p2;
52 
53  return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0);
54 }
55 
56 /* There will be one of those per vertex
57  * (simple case, computing one normal per vertex), or per smooth fan. */
59  float normal[3];
60 
61  int loops_num; /* Count number of loops using this item so far. */
62  float curr_val; /* Current max val for this item. */
63  int curr_strength; /* Current max strength encountered for this item. */
65 
66 #define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128
67 
68 typedef struct WeightedNormalData {
69  const int verts_num;
70  const int edges_num;
71  const int loops_num;
72  const int polys_num;
73 
75  const float (*vert_normals)[3];
77 
79  short (*clnors)[2];
80  const bool has_clnors; /* True if clnors already existed, false if we had to create them. */
81  const float split_angle;
82 
84  const float (*polynors)[3];
85  const int *poly_strength;
86 
88  const int defgrp_index;
89  const bool use_invert_vgroup;
90 
91  const float weight;
92  const short mode;
93 
94  /* Lower-level, internal processing data. */
96 
98 
100 
103 
110  const int mp_index)
111 {
112  BLI_assert(wn_data->poly_strength != NULL);
113 
114  const int mp_strength = wn_data->poly_strength[mp_index];
115 
116  if (mp_strength > item_data->curr_strength) {
117  item_data->curr_strength = mp_strength;
118  item_data->curr_val = 0.0f;
119  item_data->loops_num = 0;
120  zero_v3(item_data->normal);
121  }
122 
123  return mp_strength == item_data->curr_strength;
124 }
125 
127  WeightedNormalData *wn_data,
129  const int mv_index,
130  const int mp_index,
131  const float curr_val,
132  const bool use_face_influence)
133 {
134  const float(*polynors)[3] = wn_data->polynors;
135 
136  MDeformVert *dvert = wn_data->dvert;
137  const int defgrp_index = wn_data->defgrp_index;
138  const bool use_invert_vgroup = wn_data->use_invert_vgroup;
139 
140  const float weight = wn_data->weight;
141 
142  float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight;
143 
144  const bool has_vgroup = dvert != NULL;
145  const bool vert_of_group = has_vgroup &&
146  BKE_defvert_find_index(&dvert[mv_index], defgrp_index) != NULL;
147 
148  if (has_vgroup &&
149  ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) {
150  return;
151  }
152 
153  if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) {
154  return;
155  }
156 
157  /* If item's curr_val is 0 init it to present value. */
158  if (item_data->curr_val == 0.0f) {
159  item_data->curr_val = curr_val;
160  }
161  if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) {
162  /* item's curr_val and present value differ more than threshold, update. */
163  item_data->loops_num++;
164  item_data->curr_val = curr_val;
165  }
166 
167  /* Exponentially divided weight for each normal
168  * (since a few values will be used by most cases, we cache those). */
169  const int loops_num = item_data->loops_num;
170  if (loops_num < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT &&
171  cached_inverse_powers_of_weight[loops_num] == 0.0f) {
172  cached_inverse_powers_of_weight[loops_num] = 1.0f / powf(weight, loops_num);
173  }
174  const float inverted_n_weight = loops_num < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ?
175  cached_inverse_powers_of_weight[loops_num] :
176  1.0f / powf(weight, loops_num);
177 
178  madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight);
179 }
180 
182  WeightedNormalData *wn_data)
183 {
184  const int verts_num = wn_data->verts_num;
185  const int edges_num = wn_data->edges_num;
186  const int loops_num = wn_data->loops_num;
187  const int polys_num = wn_data->polys_num;
188 
189  MVert *mvert = wn_data->mvert;
190  MEdge *medge = wn_data->medge;
191 
192  MLoop *mloop = wn_data->mloop;
193  short(*clnors)[2] = wn_data->clnors;
194  int *loop_to_poly = wn_data->loop_to_poly;
195 
196  MPoly *mpoly = wn_data->mpoly;
197  const float(*polynors)[3] = wn_data->polynors;
198  const int *poly_strength = wn_data->poly_strength;
199 
200  MDeformVert *dvert = wn_data->dvert;
201 
202  const short mode = wn_data->mode;
203  ModePair *mode_pair = wn_data->mode_pair;
204 
205  const bool has_clnors = wn_data->has_clnors;
206  const float split_angle = wn_data->split_angle;
207  MLoopNorSpaceArray lnors_spacearr = {NULL};
208 
209  const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
210  const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 &&
211  poly_strength != NULL;
212  const bool has_vgroup = dvert != NULL;
213 
214  float(*loop_normals)[3] = NULL;
215 
217  int items_num = 0;
218  if (keep_sharp) {
219  BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_num, __func__);
220 
221  /* This will give us loop normal spaces,
222  * we do not actually care about computed loop_normals for now... */
223  loop_normals = MEM_calloc_arrayN((size_t)loops_num, sizeof(*loop_normals), __func__);
225  wn_data->vert_normals,
226  verts_num,
227  medge,
228  edges_num,
229  mloop,
230  loop_normals,
231  loops_num,
232  mpoly,
233  polynors,
234  polys_num,
235  true,
236  split_angle,
237  &lnors_spacearr,
238  has_clnors ? clnors : NULL,
239  loop_to_poly);
240 
241  items_num = lnors_spacearr.spaces_num;
242  items_data = MEM_calloc_arrayN((size_t)items_num, sizeof(*items_data), __func__);
243 
244  /* In this first loop, we assign each WeightedNormalDataAggregateItem
245  * to its smooth fan of loops (aka lnor space). */
246  MPoly *mp;
247  int mp_index;
248  int item_index;
249  for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < polys_num; mp++, mp_index++) {
250  int ml_index = mp->loopstart;
251  const int ml_end_index = ml_index + mp->totloop;
252 
253  for (; ml_index < ml_end_index; ml_index++) {
254  if (BLI_BITMAP_TEST(done_loops, ml_index)) {
255  /* Smooth fan of this loop has already been processed, skip it. */
256  continue;
257  }
258  BLI_assert(item_index < items_num);
259 
260  WeightedNormalDataAggregateItem *itdt = &items_data[item_index];
262 
263  MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index];
264  lnor_space->user_data = itdt;
265 
266  if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) {
267  for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) {
268  const int ml_fan_index = POINTER_AS_INT(lnode->link);
269  BLI_BITMAP_ENABLE(done_loops, ml_fan_index);
270  }
271  }
272  else {
273  BLI_BITMAP_ENABLE(done_loops, ml_index);
274  }
275 
276  item_index++;
277  }
278  }
279 
280  MEM_freeN(done_loops);
281  }
282  else {
283  items_num = verts_num;
284  items_data = MEM_calloc_arrayN((size_t)items_num, sizeof(*items_data), __func__);
285  if (use_face_influence) {
286  for (int item_index = 0; item_index < items_num; item_index++) {
287  items_data[item_index].curr_strength = FACE_STRENGTH_WEAK;
288  }
289  }
290  }
291  wn_data->items_data = items_data;
292 
293  switch (mode) {
295  for (int i = 0; i < polys_num; i++) {
296  const int mp_index = mode_pair[i].index;
297  const float mp_val = mode_pair[i].val;
298 
299  int ml_index = mpoly[mp_index].loopstart;
300  const int ml_index_end = ml_index + mpoly[mp_index].totloop;
301  for (; ml_index < ml_index_end; ml_index++) {
302  const int mv_index = mloop[ml_index].v;
304  keep_sharp ? lnors_spacearr.lspacearr[ml_index]->user_data : &items_data[mv_index];
305 
307  wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence);
308  }
309  }
310  break;
313  BLI_assert(loop_to_poly != NULL);
314 
315  for (int i = 0; i < loops_num; i++) {
316  const int ml_index = mode_pair[i].index;
317  const float ml_val = mode_pair[i].val;
318 
319  const int mp_index = loop_to_poly[ml_index];
320  const int mv_index = mloop[ml_index].v;
322  keep_sharp ? lnors_spacearr.lspacearr[ml_index]->user_data : &items_data[mv_index];
323 
325  wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence);
326  }
327  break;
328  default:
330  }
331 
332  /* Validate computed weighted normals. */
333  for (int item_index = 0; item_index < items_num; item_index++) {
334  if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) {
335  zero_v3(items_data[item_index].normal);
336  }
337  }
338 
339  if (keep_sharp) {
340  /* Set loop normals for normal computed for each lnor space (smooth fan).
341  * Note that loop_normals is already populated with clnors
342  * (before this modifier is applied, at start of this function),
343  * so no need to recompute them here. */
344  for (int ml_index = 0; ml_index < loops_num; ml_index++) {
345  WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data;
346  if (!is_zero_v3(item_data->normal)) {
347  copy_v3_v3(loop_normals[ml_index], item_data->normal);
348  }
349  }
350 
352  wn_data->vert_normals,
353  verts_num,
354  medge,
355  edges_num,
356  mloop,
357  loop_normals,
358  loops_num,
359  mpoly,
360  polynors,
361  polys_num,
362  clnors);
363  }
364  else {
365  /* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set()
366  * to keep current clnors instead of resetting them to default auto-computed ones,
367  * when given new custom normal is zero-vec.
368  * But this is not exactly trivial change, better to keep this optimization for later...
369  */
370  if (!has_vgroup) {
371  /* NOTE: in theory, we could avoid this extra allocation & copying...
372  * But think we can live with it for now,
373  * and it makes code simpler & cleaner. */
374  float(*vert_normals)[3] = MEM_calloc_arrayN(
375  (size_t)verts_num, sizeof(*loop_normals), __func__);
376 
377  for (int ml_index = 0; ml_index < loops_num; ml_index++) {
378  const int mv_index = mloop[ml_index].v;
379  copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal);
380  }
381 
383  wn_data->vert_normals,
384  vert_normals,
385  verts_num,
386  medge,
387  edges_num,
388  mloop,
389  loops_num,
390  mpoly,
391  polynors,
392  polys_num,
393  clnors);
394 
395  MEM_freeN(vert_normals);
396  }
397  else {
398  loop_normals = MEM_calloc_arrayN((size_t)loops_num, sizeof(*loop_normals), __func__);
399 
401  wn_data->vert_normals,
402  verts_num,
403  medge,
404  edges_num,
405  mloop,
406  loop_normals,
407  loops_num,
408  mpoly,
409  polynors,
410  polys_num,
411  true,
412  split_angle,
413  NULL,
414  has_clnors ? clnors : NULL,
415  loop_to_poly);
416 
417  for (int ml_index = 0; ml_index < loops_num; ml_index++) {
418  const int item_index = mloop[ml_index].v;
419  if (!is_zero_v3(items_data[item_index].normal)) {
420  copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal);
421  }
422  }
423 
425  wn_data->vert_normals,
426  verts_num,
427  medge,
428  edges_num,
429  mloop,
430  loop_normals,
431  loops_num,
432  mpoly,
433  polynors,
434  polys_num,
435  clnors);
436  }
437  }
438 
439  if (keep_sharp) {
440  BKE_lnor_spacearr_free(&lnors_spacearr);
441  }
442  MEM_SAFE_FREE(loop_normals);
443 }
444 
446 {
447  const int polys_num = wn_data->polys_num;
448 
449  MVert *mvert = wn_data->mvert;
450  MLoop *mloop = wn_data->mloop;
451  MPoly *mpoly = wn_data->mpoly;
452 
453  MPoly *mp;
454  int mp_index;
455 
456  ModePair *face_area = MEM_malloc_arrayN((size_t)polys_num, sizeof(*face_area), __func__);
457 
458  ModePair *f_area = face_area;
459  for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++, f_area++) {
460  f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert);
461  f_area->index = mp_index;
462  }
463 
464  qsort(face_area, polys_num, sizeof(*face_area), modepair_cmp_by_val_inverse);
465 
466  wn_data->mode_pair = face_area;
467  apply_weights_vertex_normal(wnmd, wn_data);
468 }
469 
471 {
472  const int loops_num = wn_data->loops_num;
473  const int polys_num = wn_data->polys_num;
474 
475  MVert *mvert = wn_data->mvert;
476  MLoop *mloop = wn_data->mloop;
477  MPoly *mpoly = wn_data->mpoly;
478 
479  MPoly *mp;
480  int mp_index;
481 
482  int *loop_to_poly = MEM_malloc_arrayN((size_t)loops_num, sizeof(*loop_to_poly), __func__);
483 
484  ModePair *corner_angle = MEM_malloc_arrayN((size_t)loops_num, sizeof(*corner_angle), __func__);
485 
486  for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++) {
487  MLoop *ml_start = &mloop[mp->loopstart];
488 
489  float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
490  BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
491 
492  ModePair *c_angl = &corner_angle[mp->loopstart];
493  float *angl = index_angle;
494  for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop;
495  ml_index++, c_angl++, angl++) {
496  c_angl->val = (float)M_PI - *angl;
497  c_angl->index = ml_index;
498 
499  loop_to_poly[ml_index] = mp_index;
500  }
501  MEM_freeN(index_angle);
502  }
503 
504  qsort(corner_angle, loops_num, sizeof(*corner_angle), modepair_cmp_by_val_inverse);
505 
506  wn_data->loop_to_poly = loop_to_poly;
507  wn_data->mode_pair = corner_angle;
508  apply_weights_vertex_normal(wnmd, wn_data);
509 }
510 
512 {
513  const int loops_num = wn_data->loops_num;
514  const int polys_num = wn_data->polys_num;
515 
516  MVert *mvert = wn_data->mvert;
517  MLoop *mloop = wn_data->mloop;
518  MPoly *mpoly = wn_data->mpoly;
519 
520  MPoly *mp;
521  int mp_index;
522 
523  int *loop_to_poly = MEM_malloc_arrayN((size_t)loops_num, sizeof(*loop_to_poly), __func__);
524 
525  ModePair *combined = MEM_malloc_arrayN((size_t)loops_num, sizeof(*combined), __func__);
526 
527  for (mp_index = 0, mp = mpoly; mp_index < polys_num; mp_index++, mp++) {
528  MLoop *ml_start = &mloop[mp->loopstart];
529 
530  float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert);
531  float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
532  BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
533 
534  ModePair *cmbnd = &combined[mp->loopstart];
535  float *angl = index_angle;
536  for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop;
537  ml_index++, cmbnd++, angl++) {
538  /* In this case val is product of corner angle and face area. */
539  cmbnd->val = ((float)M_PI - *angl) * face_area;
540  cmbnd->index = ml_index;
541 
542  loop_to_poly[ml_index] = mp_index;
543  }
544  MEM_freeN(index_angle);
545  }
546 
547  qsort(combined, loops_num, sizeof(*combined), modepair_cmp_by_val_inverse);
548 
549  wn_data->loop_to_poly = loop_to_poly;
550  wn_data->mode_pair = combined;
551  apply_weights_vertex_normal(wnmd, wn_data);
552 }
553 
555 {
557  Object *ob = ctx->object;
558 
559  /* XXX TODO(Rohan Rathi):
560  * Once we fully switch to Mesh evaluation of modifiers,
561  * we can expect to get that flag from the COW copy.
562  * But for now, it is lost in the DM intermediate step,
563  * so we need to directly check orig object's data. */
564 #if 0
565  if (!(mesh->flag & ME_AUTOSMOOTH))
566 #else
567  if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
568 #endif
569  {
571  ctx->object, (ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties");
572  return mesh;
573  }
574 
575  Mesh *result;
577 
578  const int verts_num = result->totvert;
579  const int edges_num = result->totedge;
580  const int loops_num = result->totloop;
581  const int polys_num = result->totpoly;
582 
583  MEdge *medge = result->medge;
584  MPoly *mpoly = result->mpoly;
585  MVert *mvert = result->mvert;
586  MLoop *mloop = result->mloop;
587 
588  /* Right now:
589  * If weight = 50 then all faces are given equal weight.
590  * If weight > 50 then more weight given to faces with larger vals (face area / corner angle).
591  * If weight < 50 then more weight given to faces with lesser vals. However current calculation
592  * does not converge to min/max.
593  */
594  float weight = ((float)wnmd->weight) / 50.0f;
595  if (wnmd->weight == 100) {
596  weight = (float)SHRT_MAX;
597  }
598  else if (wnmd->weight == 1) {
599  weight = 1 / (float)SHRT_MAX;
600  }
601  else if ((weight - 1) * 25 > 1) {
602  weight = (weight - 1) * 25;
603  }
604 
605  const float split_angle = mesh->smoothresh;
606  short(*clnors)[2] = CustomData_get_layer(&result->ldata, CD_CUSTOMLOOPNORMAL);
607 
608  /* Keep info whether we had clnors,
609  * it helps when generating clnor spaces and default normals. */
610  const bool has_clnors = clnors != NULL;
611  if (!clnors) {
612  clnors = CustomData_add_layer(&result->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, loops_num);
613  }
614 
615  MDeformVert *dvert;
616  int defgrp_index;
617  MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index);
618 
619  WeightedNormalData wn_data = {
620  .verts_num = verts_num,
621  .edges_num = edges_num,
622  .loops_num = loops_num,
623  .polys_num = polys_num,
624 
625  .mvert = mvert,
626  .vert_normals = BKE_mesh_vertex_normals_ensure(result),
627  .medge = medge,
628 
629  .mloop = mloop,
630  .clnors = clnors,
631  .has_clnors = has_clnors,
632  .split_angle = split_angle,
633 
634  .mpoly = mpoly,
635  .polynors = BKE_mesh_poly_normals_ensure(mesh),
636  .poly_strength = CustomData_get_layer_named(
638 
639  .dvert = dvert,
640  .defgrp_index = defgrp_index,
641  .use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0,
642 
643  .weight = weight,
644  .mode = wnmd->mode,
645  };
646 
647  switch (wnmd->mode) {
649  wn_face_area(wnmd, &wn_data);
650  break;
652  wn_corner_angle(wnmd, &wn_data);
653  break;
655  wn_face_with_angle(wnmd, &wn_data);
656  break;
657  }
658 
659  MEM_SAFE_FREE(wn_data.loop_to_poly);
660  MEM_SAFE_FREE(wn_data.mode_pair);
661  MEM_SAFE_FREE(wn_data.items_data);
662 
663  result->runtime.is_original = false;
664 
665  return result;
666 }
667 
668 static void initData(ModifierData *md)
669 {
671 
672  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wnmd, modifier));
673 
675 }
676 
677 static void requiredDataMask(Object *UNUSED(ob),
678  ModifierData *md,
679  CustomData_MeshMasks *r_cddata_masks)
680 {
682 
683  r_cddata_masks->lmask = CD_MASK_CUSTOMLOOPNORMAL;
684 
685  if (wnmd->defgrp_name[0] != '\0') {
686  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
687  }
688 
690  r_cddata_masks->pmask |= CD_MASK_PROP_INT32;
691  }
692 }
693 
695 {
696  return true;
697 }
698 
699 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
700 {
701  uiLayout *col;
702  uiLayout *layout = panel->layout;
703 
704  PointerRNA ob_ptr;
706 
707  uiLayoutSetPropSep(layout, true);
708 
709  uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
710 
711  uiItemR(layout, ptr, "weight", 0, IFACE_("Weight"), ICON_NONE);
712  uiItemR(layout, ptr, "thresh", 0, IFACE_("Threshold"), ICON_NONE);
713 
714  col = uiLayoutColumn(layout, false);
715  uiItemR(col, ptr, "keep_sharp", 0, NULL, ICON_NONE);
716  uiItemR(col, ptr, "use_face_influence", 0, NULL, ICON_NONE);
717 
718  modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
719 
720  modifier_panel_end(layout, ptr);
721 }
722 
723 static void panelRegister(ARegionType *region_type)
724 {
726 }
727 
729  /* name */ N_("WeightedNormal"),
730  /* structName */ "WeightedNormalModifierData",
731  /* structSize */ sizeof(WeightedNormalModifierData),
732  /* srna */ &RNA_WeightedNormalModifier,
736  /* icon */ ICON_MOD_NORMALEDIT,
737 
738  /* copyData */ BKE_modifier_copydata_generic,
739 
740  /* deformVerts */ NULL,
741  /* deformMatrices */ NULL,
742  /* deformVertsEM */ NULL,
743  /* deformMatricesEM */ NULL,
744  /* modifyMesh */ modifyMesh,
745  /* modifyGeometrySet */ NULL,
746 
747  /* initData */ initData,
748  /* requiredDataMask */ requiredDataMask,
749  /* freeData */ NULL,
750  /* isDisabled */ NULL,
751  /* updateDepsgraph */ NULL,
752  /* dependsOnTime */ NULL,
753  /* dependsOnNormals */ dependsOnNormals,
754  /* foreachIDLink */ NULL,
755  /* foreachTexLink */ NULL,
756  /* freeRuntimeData */ NULL,
757  /* panelRegister */ panelRegister,
758  /* blendWrite */ NULL,
759  /* blendRead */ NULL,
760 };
typedef float(TangentPoint)[2]
@ CD_CALLOC
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
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
support for deformation groups and hooks.
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, int defgroup)
@ LIB_ID_COPY_LOCALIZE
Definition: BKE_lib_id.h:187
struct ID * BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, int flag)
const float(* BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3]
void BKE_mesh_calc_poly_angles(const struct MPoly *mpoly, const struct MLoop *loopstart, const struct MVert *mvarray, float angles[])
void BKE_mesh_normals_loop_custom_set(const struct MVert *mverts, const float(*vert_normals)[3], int numVerts, struct MEdge *medges, int numEdges, struct MLoop *mloops, float(*r_custom_loopnors)[3], int numLoops, struct MPoly *mpolys, const float(*polynors)[3], int numPolys, short(*r_clnors_data)[2])
void BKE_mesh_normals_loop_custom_from_vertices_set(const struct MVert *mverts, const float(*vert_normals)[3], float(*r_custom_vertnors)[3], int numVerts, struct MEdge *medges, int numEdges, struct MLoop *mloops, int numLoops, struct MPoly *mpolys, const float(*polynors)[3], int numPolys, short(*r_clnors_data)[2])
const float(* BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3]
void BKE_mesh_normals_loop_split(const struct MVert *mverts, const float(*vert_normals)[3], int numVerts, struct MEdge *medges, int numEdges, struct MLoop *mloops, float(*r_loopnors)[3], int numLoops, struct MPoly *mpolys, const float(*polynors)[3], int numPolys, bool use_split_normals, float split_angle, MLoopNorSpaceArray *r_lnors_spacearr, short(*clnors_data)[2], int *r_loop_to_poly)
@ MLNOR_SPACE_IS_SINGLE
Definition: BKE_mesh.h:553
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly, const struct MLoop *loopstart, const struct MVert *mvarray)
@ eModifierTypeFlag_SupportsMapping
Definition: BKE_modifier.h:68
@ eModifierTypeFlag_EnableInEditmode
Definition: BKE_modifier.h:78
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:69
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:66
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, int flag)
@ eModifierTypeType_Constructive
Definition: BKE_modifier.h:47
void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#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 M_PI
Definition: BLI_math_base.h:20
MINLINE int compare_ff(float a, float b, float max_diff)
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define IFACE_(msgid)
#define CD_MASK_MDEFORMVERT
@ CD_CUSTOMLOOPNORMAL
@ CD_PROP_INT32
#define CD_MASK_PROP_INT32
#define CD_MASK_CUSTOMLOOPNORMAL
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
@ ME_AUTOSMOOTH
struct WeightedNormalModifierData WeightedNormalModifierData
@ eModifierType_WeightedNormal
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID
@ MOD_WEIGHTEDNORMAL_KEEP_SHARP
@ MOD_WEIGHTEDNORMAL_FACE_INFLUENCE
@ MOD_WEIGHTEDNORMAL_INVERT_VGROUP
@ MOD_WEIGHTEDNORMAL_MODE_FACE
@ MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE
@ MOD_WEIGHTEDNORMAL_MODE_ANGLE
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
Definition: MOD_ui_common.c:91
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
void MOD_get_vgroup(Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index)
Definition: MOD_util.c:235
static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
static Mesh * modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static bool check_item_poly_strength(WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mp_index)
static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
#define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT
struct ModePair ModePair
static bool dependsOnNormals(ModifierData *UNUSED(md))
ModifierTypeInfo modifierType_WeightedNormal
struct WeightedNormalData WeightedNormalData
static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
struct WeightedNormalDataAggregateItem WeightedNormalDataAggregateItem
#define CLNORS_VALID_VEC_LEN
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void initData(ModifierData *md)
static void panelRegister(ARegionType *region_type)
static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
static void aggregate_item_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mv_index, const int mp_index, const float curr_val, const bool use_face_influence)
static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
#define C
Definition: RandGen.cpp:25
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
@ FACE_STRENGTH_WEAK
#define powf(x, y)
Definition: cuda/compat.h:103
uint col
IconTextureDrawCall normal
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
struct LinkNode * next
Definition: BLI_linklist.h:23
MLoopNorSpace ** lspacearr
Definition: BKE_mesh.h:560
void * user_data
Definition: BKE_mesh.h:547
struct LinkNode * loops
Definition: BKE_mesh.h:543
unsigned int v
float smoothresh
uint16_t flag
struct Object * object
Definition: BKE_modifier.h:141
void * data
struct uiLayout * layout
const float(* vert_normals)[3]
WeightedNormalDataAggregateItem * items_data
const float(* polynors)[3]
float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT]
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480