Cleanup: BKE_library: remove 'test' param of id_copy.
[blender.git] / source / blender / modifiers / intern / MOD_weighted_normal.c
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
17 /** \file blender/modifiers/intern/MOD_weighted_normal.c
18  *  \ingroup modifiers
19  */
20
21 #include "MEM_guardedalloc.h"
22
23 #include "DNA_mesh_types.h"
24 #include "DNA_object_types.h"
25 #include "DNA_scene_types.h"
26
27 #include "BKE_cdderivedmesh.h"
28 #include "BKE_deform.h"
29 #include "BKE_library.h"
30 #include "BKE_mesh.h"
31
32 #include "BLI_math.h"
33 #include "BLI_linklist.h"
34
35 #include "MOD_modifiertypes.h"
36 #include "MOD_util.h"
37
38 #define CLNORS_VALID_VEC_LEN (1e-6f)
39
40 typedef struct ModePair {
41         float val;  /* Contains mode based value (face area / corner angle). */
42         int index;  /* Index value per poly or per loop. */
43 } ModePair;
44
45 /* Sorting function used in modifier, sorts in decreasing order. */
46 static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
47 {
48         ModePair *r1 = (ModePair *)p1;
49         ModePair *r2 = (ModePair *)p2;
50
51         return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0);
52 }
53
54 /* There will be one of those per vertex (simple case, computing one normal per vertex), or per smooth fan. */
55 typedef struct WeightedNormalDataAggregateItem {
56         float normal[3];
57
58         int num_loops;  /* Count number of loops using this item so far. */
59         float curr_val;  /* Current max val for this item. */
60         int curr_strength;  /* Current max strength encountered for this item. */
61 } WeightedNormalDataAggregateItem;
62
63 #define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128
64
65 typedef struct WeightedNormalData {
66         const int numVerts;
67         const int numEdges;
68         const int numLoops;
69         const int numPolys;
70
71         MVert *mvert;
72         MEdge *medge;
73
74         MLoop *mloop;
75         short (*clnors)[2];
76         const bool has_clnors;  /* True if clnors already existed, false if we had to create them. */
77         const float split_angle;
78
79         MPoly *mpoly;
80         float (*polynors)[3];
81         int *poly_strength;
82
83         MDeformVert *dvert;
84         const int defgrp_index;
85         const bool use_invert_vgroup;
86
87         const float weight;
88         const short mode;
89
90         /* Lower-level, internal processing data. */
91         float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT];
92
93         WeightedNormalDataAggregateItem *items_data;
94
95         ModePair *mode_pair;
96
97         int *loop_to_poly;
98 } WeightedNormalData;
99
100 /* Check strength of given poly compared to those found so far for that given item (vertex or smooth fan),
101  * and reset matching item_data in case we get a stronger new strength. */
102 static bool check_item_poly_strength(
103         WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mp_index)
104 {
105         BLI_assert (wn_data->poly_strength != NULL);
106
107         const int mp_strength = wn_data->poly_strength[mp_index];
108
109         if (mp_strength > item_data->curr_strength) {
110                 item_data->curr_strength = mp_strength;
111                 item_data->curr_val = 0.0f;
112                 item_data->num_loops = 0;
113                 zero_v3(item_data->normal);
114         }
115
116         return mp_strength == item_data->curr_strength;
117 }
118
119 static void aggregate_item_normal(
120         WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data,
121         WeightedNormalDataAggregateItem *item_data,
122         const int mv_index, const int mp_index,
123         const float curr_val, const bool use_face_influence)
124 {
125         float (*polynors)[3] = wn_data->polynors;
126
127         MDeformVert *dvert = wn_data->dvert;
128         const int defgrp_index = wn_data->defgrp_index;
129         const bool use_invert_vgroup = wn_data->use_invert_vgroup;
130
131         const float weight = wn_data->weight;
132
133         float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight;
134
135         const bool has_vgroup = dvert != NULL;
136         const bool vert_of_group = has_vgroup && defvert_find_index(&dvert[mv_index], defgrp_index) != NULL;
137
138         if (has_vgroup && ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) {
139                 return;
140         }
141
142         if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) {
143                 return;
144         }
145
146         /* If item's curr_val is 0 init it to present value. */
147         if (item_data->curr_val == 0.0f) {
148                 item_data->curr_val = curr_val;
149         }
150         if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) {
151                 /* item's curr_val and present value differ more than threshold, update. */
152                 item_data->num_loops++;
153                 item_data->curr_val = curr_val;
154         }
155
156         /* Exponentially divided weight for each normal (since a few values will be used by most cases, we cache those). */
157         const int num_loops = item_data->num_loops;
158         if (num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT && cached_inverse_powers_of_weight[num_loops] == 0.0f) {
159                 cached_inverse_powers_of_weight[num_loops] = 1.0f / powf(weight, num_loops);
160         }
161         const float inverted_n_weight = num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ?
162                                             cached_inverse_powers_of_weight[num_loops] : 1.0f / powf(weight, num_loops);
163
164         madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight);
165 }
166
167 static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
168 {
169         const int numVerts = wn_data->numVerts;
170         const int numEdges = wn_data->numEdges;
171         const int numLoops = wn_data->numLoops;
172         const int numPolys = wn_data->numPolys;
173
174         MVert *mvert = wn_data->mvert;
175         MEdge *medge = wn_data->medge;
176
177         MLoop *mloop = wn_data->mloop;
178         short (*clnors)[2] = wn_data->clnors;
179         int *loop_to_poly = wn_data->loop_to_poly;
180
181         MPoly *mpoly = wn_data->mpoly;
182         float (*polynors)[3] = wn_data->polynors;
183         int *poly_strength = wn_data->poly_strength;
184
185         MDeformVert *dvert = wn_data->dvert;
186
187         const short mode = wn_data->mode;
188         ModePair *mode_pair = wn_data->mode_pair;
189
190         const bool has_clnors = wn_data->has_clnors;
191         const float split_angle = wn_data->split_angle;
192         MLoopNorSpaceArray lnors_spacearr = {NULL};
193
194         const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
195         const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && poly_strength != NULL;
196         const bool has_vgroup = dvert != NULL;
197
198         float (*loop_normals)[3] = NULL;
199
200         WeightedNormalDataAggregateItem *items_data = NULL;
201         int num_items = 0;
202         if (keep_sharp) {
203                 BLI_bitmap *done_loops = BLI_BITMAP_NEW(numLoops, __func__);
204
205                 /* This will give us loop normal spaces, we do not actually care about computed loop_normals for now... */
206                 loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
207                 BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges,
208                                             mloop, loop_normals, numLoops, mpoly, polynors, numPolys,
209                                             true, split_angle, &lnors_spacearr, has_clnors ? clnors : NULL, loop_to_poly);
210
211                 num_items = lnors_spacearr.num_spaces;
212                 items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
213
214                 /* In this first loop, we assign each WeightedNormalDataAggregateItem
215                  * to its smooth fan of loops (aka lnor space). */
216                 MPoly *mp;
217                 int mp_index;
218                 int item_index;
219                 for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < numPolys; mp++, mp_index++) {
220                         int ml_index = mp->loopstart;
221                         const int ml_end_index = ml_index + mp->totloop;
222
223                         for (; ml_index < ml_end_index; ml_index++) {
224                                 if (BLI_BITMAP_TEST(done_loops, ml_index)) {
225                                         /* Smooth fan of this loop has already been processed, skip it. */
226                                         continue;
227                                 }
228                                 BLI_assert(item_index < num_items);
229
230                                 WeightedNormalDataAggregateItem *itdt = &items_data[item_index];
231                                 itdt->curr_strength = FACE_STRENGTH_WEAK;
232
233                                 MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index];
234                                 lnor_space->user_data = itdt;
235
236                                 if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) {
237                                         for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) {
238                                                 const int ml_fan_index = POINTER_AS_INT(lnode->link);
239                                                 BLI_BITMAP_ENABLE(done_loops, ml_fan_index);
240                                         }
241                                 }
242                                 else {
243                                         BLI_BITMAP_ENABLE(done_loops, ml_index);
244                                 }
245
246                                 item_index++;
247                         }
248                 }
249
250                 MEM_freeN(done_loops);
251         }
252         else {
253                 num_items = numVerts;
254                 items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
255                 if (use_face_influence) {
256                         for (int item_index = 0; item_index < num_items; item_index++) {
257                                 items_data[item_index].curr_strength = FACE_STRENGTH_WEAK;
258                         }
259                 }
260         }
261         wn_data->items_data = items_data;
262
263         switch (mode) {
264                 case MOD_WEIGHTEDNORMAL_MODE_FACE:
265                         for (int i = 0; i < numPolys; i++) {
266                                 const int mp_index = mode_pair[i].index;
267                                 const float mp_val = mode_pair[i].val;
268
269                                 int ml_index = mpoly[mp_index].loopstart;
270                                 const int ml_index_end = ml_index + mpoly[mp_index].totloop;
271                                 for (; ml_index < ml_index_end; ml_index++) {
272                                         const int mv_index = mloop[ml_index].v;
273                                         WeightedNormalDataAggregateItem *item_data = keep_sharp ?
274                                                                                          lnors_spacearr.lspacearr[ml_index]->user_data:
275                                                                                          &items_data[mv_index];
276
277                                         aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence);
278                                 }
279                         }
280                         break;
281                 case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
282                 case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
283                         BLI_assert(loop_to_poly != NULL);
284
285                         for (int i = 0; i < numLoops; i++) {
286                                 const int ml_index = mode_pair[i].index;
287                                 const float ml_val = mode_pair[i].val;
288
289                                 const int mp_index = loop_to_poly[ml_index];
290                                 const int mv_index = mloop[ml_index].v;
291                                 WeightedNormalDataAggregateItem *item_data = keep_sharp ?
292                                                                                  lnors_spacearr.lspacearr[ml_index]->user_data:
293                                                                                  &items_data[mv_index];
294
295                                 aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence);
296                         }
297                         break;
298                 default:
299                         BLI_assert(0);
300         }
301
302         /* Validate computed weighted normals. */
303         for (int item_index = 0; item_index < num_items; item_index++) {
304                 if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) {
305                         zero_v3(items_data[item_index].normal);
306                 }
307         }
308
309         if (keep_sharp) {
310                 /* Set loop normals for normal computed for each lnor space (smooth fan).
311                  * Note that loop_normals is already populated with clnors (before this modifier is applied, at start of
312                  * this function), so no need to recompute them here. */
313                 for (int ml_index = 0; ml_index < numLoops; ml_index++) {
314                         WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data;
315                         if (!is_zero_v3(item_data->normal)) {
316                                 copy_v3_v3(loop_normals[ml_index], item_data->normal);
317                         }
318                 }
319
320                 BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges,
321                                                  mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors);
322         }
323         else {
324                 /* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set() to keep current
325                  * clnors instead of resetting them to default autocomputed ones, when given new custom normal is zero-vec.
326                  * But this is not exactly trivial change, better to keep this optimization for later...
327                  */
328                 if (!has_vgroup) {
329                         /* Note: in theory, we could avoid this extra allocation & copying... But think we can live with it for now,
330                          * and it makes code simpler & cleaner. */
331                         float (*vert_normals)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*loop_normals), __func__);
332
333                         for (int ml_index = 0; ml_index < numLoops; ml_index++) {
334                                 const int mv_index = mloop[ml_index].v;
335                                 copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal);
336                         }
337
338                         BKE_mesh_normals_loop_custom_from_vertices_set(mvert, vert_normals, numVerts, medge, numEdges,
339                                                                        mloop, numLoops, mpoly, polynors, numPolys, clnors);
340
341                         MEM_freeN(vert_normals);
342                 }
343                 else {
344                         loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
345
346                         BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges,
347                                                     mloop, loop_normals, numLoops, mpoly, polynors, numPolys,
348                                                     true, split_angle, NULL, has_clnors ? clnors : NULL, loop_to_poly);
349
350                         for (int ml_index = 0; ml_index < numLoops; ml_index++) {
351                                 const int item_index = mloop[ml_index].v;
352                                 if (!is_zero_v3(items_data[item_index].normal)) {
353                                         copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal);
354                                 }
355                         }
356
357                         BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges,
358                                                          mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors);
359                 }
360         }
361
362         if (keep_sharp) {
363                 BKE_lnor_spacearr_free(&lnors_spacearr);
364         }
365         MEM_SAFE_FREE(loop_normals);
366 }
367
368 static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
369 {
370         const int numPolys = wn_data->numPolys;
371
372         MVert *mvert = wn_data->mvert;
373         MLoop *mloop = wn_data->mloop;
374         MPoly *mpoly = wn_data->mpoly;
375
376         MPoly *mp;
377         int mp_index;
378
379         ModePair *face_area = MEM_malloc_arrayN((size_t)numPolys, sizeof(*face_area), __func__);
380
381         ModePair *f_area = face_area;
382         for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++, f_area++) {
383                 f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert);
384                 f_area->index = mp_index;
385         }
386
387         qsort(face_area, numPolys, sizeof(*face_area), modepair_cmp_by_val_inverse);
388
389         wn_data->mode_pair = face_area;
390         apply_weights_vertex_normal(wnmd, wn_data);
391 }
392
393 static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
394 {
395         const int numLoops = wn_data->numLoops;
396         const int numPolys = wn_data->numPolys;
397
398         MVert *mvert = wn_data->mvert;
399         MLoop *mloop = wn_data->mloop;
400         MPoly *mpoly = wn_data->mpoly;
401
402         MPoly *mp;
403         int mp_index;
404
405         int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
406
407         ModePair *corner_angle = MEM_malloc_arrayN((size_t)numLoops, sizeof(*corner_angle), __func__);
408
409         for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
410                 MLoop *ml_start = &mloop[mp->loopstart];
411
412                 float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
413                 BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
414
415                 ModePair *c_angl = &corner_angle[mp->loopstart];
416                 float *angl = index_angle;
417                 for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, c_angl++, angl++) {
418                         c_angl->val = (float)M_PI - *angl;
419                         c_angl->index = ml_index;
420
421                         loop_to_poly[ml_index] = mp_index;
422                 }
423                 MEM_freeN(index_angle);
424         }
425
426         qsort(corner_angle, numLoops, sizeof(*corner_angle), modepair_cmp_by_val_inverse);
427
428         wn_data->loop_to_poly = loop_to_poly;
429         wn_data->mode_pair = corner_angle;
430         apply_weights_vertex_normal(wnmd, wn_data);
431 }
432
433 static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
434 {
435         const int numLoops = wn_data->numLoops;
436         const int numPolys = wn_data->numPolys;
437
438         MVert *mvert = wn_data->mvert;
439         MLoop *mloop = wn_data->mloop;
440         MPoly *mpoly = wn_data->mpoly;
441
442         MPoly *mp;
443         int mp_index;
444
445         int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
446
447         ModePair *combined = MEM_malloc_arrayN((size_t)numLoops, sizeof(*combined), __func__);
448
449         for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
450                 MLoop *ml_start = &mloop[mp->loopstart];
451
452                 float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert);
453                 float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
454                 BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
455
456                 ModePair *cmbnd = &combined[mp->loopstart];
457                 float *angl = index_angle;
458                 for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, cmbnd++, angl++) {
459                         /* In this case val is product of corner angle and face area. */
460                         cmbnd->val = ((float)M_PI - *angl) * face_area;
461                         cmbnd->index = ml_index;
462
463                         loop_to_poly[ml_index] = mp_index;
464                 }
465                 MEM_freeN(index_angle);
466         }
467
468         qsort(combined, numLoops, sizeof(*combined), modepair_cmp_by_val_inverse);
469
470         wn_data->loop_to_poly = loop_to_poly;
471         wn_data->mode_pair = combined;
472         apply_weights_vertex_normal(wnmd, wn_data);
473 }
474
475 static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
476 {
477         WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
478         Object *ob = ctx->object;
479
480         /* XXX TODO ARG GRRR XYQWNMPRXTYY
481          * Once we fully switch to Mesh evaluation of modifiers, we can expect to get that flag from the COW copy.
482          * But for now, it is lost in the DM intermediate step, so we need to directly check orig object's data. */
483 #if 0
484         if (!(mesh->flag & ME_AUTOSMOOTH)) {
485 #else
486         if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) {
487 #endif
488                 modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings");
489                 return mesh;
490         }
491
492         Mesh *result;
493         BKE_id_copy_ex(
494                 NULL, &mesh->id, (ID **)&result,
495                 LIB_ID_CREATE_NO_MAIN |
496                 LIB_ID_CREATE_NO_USER_REFCOUNT |
497                 LIB_ID_CREATE_NO_DEG_TAG |
498                 LIB_ID_COPY_NO_PREVIEW);
499
500         const int numVerts = result->totvert;
501         const int numEdges = result->totedge;
502         const int numLoops = result->totloop;
503         const int numPolys = result->totpoly;
504
505         MEdge *medge = result->medge;
506         MPoly *mpoly = result->mpoly;
507         MVert *mvert = result->mvert;
508         MLoop *mloop = result->mloop;
509
510         /* Right now:
511          * If weight = 50 then all faces are given equal weight.
512          * If weight > 50 then more weight given to faces with larger vals (face area / corner angle).
513          * If weight < 50 then more weight given to faces with lesser vals. However current calculation
514          * does not converge to min/max.
515          */
516         float weight = ((float)wnmd->weight) / 50.0f;
517         if (wnmd->weight == 100) {
518                 weight = (float)SHRT_MAX;
519         }
520         else if (wnmd->weight == 1) {
521                 weight = 1 / (float)SHRT_MAX;
522         }
523         else if ((weight - 1) * 25 > 1) {
524                 weight = (weight - 1) * 25;
525         }
526
527         CustomData *pdata = &result->pdata;
528         float (*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
529         if (!polynors) {
530                 polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
531         }
532         BKE_mesh_calc_normals_poly(mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false);
533
534
535         const float split_angle = mesh->smoothresh;
536         short (*clnors)[2];
537         CustomData *ldata = &result->ldata;
538         clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
539
540         /* Keep info  whether we had clnors, it helps when generating clnor spaces and default normals. */
541         const bool has_clnors = clnors != NULL;
542         if (!clnors) {
543                 clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numLoops);
544                 clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
545         }
546
547         MDeformVert *dvert;
548         int defgrp_index;
549         MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index);
550
551         WeightedNormalData wn_data = {
552             .numVerts = numVerts,
553             .numEdges = numEdges,
554             .numLoops = numLoops,
555             .numPolys = numPolys,
556
557             .mvert = mvert,
558             .medge = medge,
559
560             .mloop = mloop,
561             .clnors = clnors,
562             .has_clnors = has_clnors,
563             .split_angle = split_angle,
564
565             .mpoly = mpoly,
566             .polynors = polynors,
567             .poly_strength = CustomData_get_layer_named(
568                     &result->pdata, CD_PROP_INT,
569                     MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID),
570
571             .dvert = dvert,
572             .defgrp_index = defgrp_index,
573             .use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0,
574
575             .weight = weight,
576             .mode = wnmd->mode,
577         };
578
579         switch (wnmd->mode) {
580                 case MOD_WEIGHTEDNORMAL_MODE_FACE:
581                         wn_face_area(wnmd, &wn_data);
582                         break;
583                 case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
584                         wn_corner_angle(wnmd, &wn_data);
585                         break;
586                 case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
587                         wn_face_with_angle(wnmd, &wn_data);
588                         break;
589         }
590
591         MEM_SAFE_FREE(wn_data.loop_to_poly);
592         MEM_SAFE_FREE(wn_data.mode_pair);
593         MEM_SAFE_FREE(wn_data.items_data);
594
595         return result;
596 }
597
598 static void initData(ModifierData *md)
599 {
600         WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
601         wnmd->mode = MOD_WEIGHTEDNORMAL_MODE_FACE;
602         wnmd->weight = 50;
603         wnmd->thresh = 1e-2f;
604         wnmd->flag = 0;
605 }
606
607 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
608 {
609         WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
610         CustomDataMask dataMask = CD_MASK_CUSTOMLOOPNORMAL;
611
612         if (wnmd->defgrp_name[0]) {
613                 dataMask |= CD_MASK_MDEFORMVERT;
614         }
615
616         if (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) {
617                 dataMask |= CD_MASK_PROP_INT;
618         }
619
620         return dataMask;
621 }
622
623 static bool dependsOnNormals(ModifierData *UNUSED(md))
624 {
625         return true;
626 }
627
628 ModifierTypeInfo modifierType_WeightedNormal = {
629         /* name */              "Weighted Normal",
630         /* structName */        "WeightedNormalModifierData",
631         /* structSize */        sizeof(WeightedNormalModifierData),
632         /* type */              eModifierTypeType_Constructive,
633         /* flags */             eModifierTypeFlag_AcceptsMesh |
634                                 eModifierTypeFlag_SupportsMapping |
635                                 eModifierTypeFlag_SupportsEditmode |
636                                 eModifierTypeFlag_EnableInEditmode,
637
638         /* copyData */          modifier_copyData_generic,
639
640         /* deformVerts_DM */    NULL,
641         /* deformMatrices_DM */ NULL,
642         /* deformVertsEM_DM */  NULL,
643         /* deformMatricesEM_DM*/NULL,
644         /* applyModifier_DM */  NULL,
645
646         /* deformVerts */       NULL,
647         /* deformMatrices */    NULL,
648         /* deformVertsEM */     NULL,
649         /* deformMatricesEM */  NULL,
650         /* applyModifier */     applyModifier,
651
652         /* initData */          initData,
653         /* requiredDataMask */  requiredDataMask,
654         /* freeData */          NULL,
655         /* isDisabled */        NULL,
656         /* updateDepsgraph */   NULL,
657         /* dependsOnTime */     NULL,
658         /* dependsOnNormals */  dependsOnNormals,
659         /* foreachObjectLink */ NULL,
660         /* foreachIDLink */     NULL,
661         /* foreachTexLink */    NULL,
662 };