Mesh Modifiers: refactor copying using a generic function
[blender.git] / source / blender / modifiers / intern / MOD_solidify.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software  Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Campbell Barton
22  *                 Shinsuke Irie
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  *
26  */
27
28 /** \file blender/modifiers/intern/MOD_solidify.c
29  *  \ingroup modifiers
30  */
31
32 #include "DNA_mesh_types.h"
33 #include "DNA_meshdata_types.h"
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_utildefines.h"
38 #include "BLI_math.h"
39 #include "BLI_string.h"
40
41 #include "BKE_cdderivedmesh.h"
42 #include "BKE_mesh.h"
43 #include "BKE_particle.h"
44 #include "BKE_deform.h"
45
46 #include "MOD_modifiertypes.h"
47 #include "MOD_util.h"
48
49 #ifdef __GNUC__
50 #  pragma GCC diagnostic error "-Wsign-conversion"
51 #endif
52
53 /* skip shell thickness for non-manifold edges, see [#35710] */
54 #define USE_NONMANIFOLD_WORKAROUND
55
56 /* *** derived mesh high quality normal calculation function  *** */
57 /* could be exposed for other functions to use */
58
59 typedef struct EdgeFaceRef {
60         int f1; /* init as -1 */
61         int f2;
62 } EdgeFaceRef;
63
64 BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
65 {
66         return !((edge_ref->f1 == 0) && (edge_ref->f2 == 0));
67 }
68
69 /**
70  * \param dm  Mesh to calculate normals for.
71  * \param face_nors  Precalculated face normals.
72  * \param r_vert_nors  Return vert normals.
73  */
74 static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_vert_nors)[3])
75 {
76         int i, numVerts, numEdges, numFaces;
77         MPoly *mpoly, *mp;
78         MLoop *mloop, *ml;
79         MEdge *medge, *ed;
80         MVert *mvert, *mv;
81
82         numVerts = dm->getNumVerts(dm);
83         numEdges = dm->getNumEdges(dm);
84         numFaces = dm->getNumPolys(dm);
85         mpoly = dm->getPolyArray(dm);
86         medge = dm->getEdgeArray(dm);
87         mvert = dm->getVertArray(dm);
88         mloop = dm->getLoopArray(dm);
89
90         /* we don't want to overwrite any referenced layers */
91
92         /* Doesn't work here! */
93 #if 0
94         mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts);
95         cddm->mvert = mv;
96 #endif
97
98         mv = mvert;
99         mp = mpoly;
100
101         {
102                 EdgeFaceRef *edge_ref_array = MEM_callocN(sizeof(EdgeFaceRef) * (size_t)numEdges, "Edge Connectivity");
103                 EdgeFaceRef *edge_ref;
104                 float edge_normal[3];
105
106                 /* This loop adds an edge hash if its not there, and adds the face index */
107                 for (i = 0; i < numFaces; i++, mp++) {
108                         int j;
109
110                         ml = mloop + mp->loopstart;
111
112                         for (j = 0; j < mp->totloop; j++, ml++) {
113                                 /* --- add edge ref to face --- */
114                                 edge_ref = &edge_ref_array[ml->e];
115                                 if (!edgeref_is_init(edge_ref)) {
116                                         edge_ref->f1 =  i;
117                                         edge_ref->f2 = -1;
118                                 }
119                                 else if ((edge_ref->f1 != -1) && (edge_ref->f2 == -1)) {
120                                         edge_ref->f2 = i;
121                                 }
122                                 else {
123                                         /* 3+ faces using an edge, we can't handle this usefully */
124                                         edge_ref->f1 = edge_ref->f2 = -1;
125 #ifdef USE_NONMANIFOLD_WORKAROUND
126                                         medge[ml->e].flag |= ME_EDGE_TMP_TAG;
127 #endif
128                                 }
129                                 /* --- done --- */
130                         }
131                 }
132
133                 for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) {
134                         /* Get the edge vert indices, and edge value (the face indices that use it) */
135
136                         if (edgeref_is_init(edge_ref) && (edge_ref->f1 != -1)) {
137                                 if (edge_ref->f2 != -1) {
138                                         /* We have 2 faces using this edge, calculate the edges normal
139                                          * using the angle between the 2 faces as a weighting */
140 #if 0
141                                         add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
142                                         normalize_v3(edge_normal);
143
144                                         mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
145 #else
146                                         mid_v3_v3v3_angle_weighted(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
147 #endif
148                                 }
149                                 else {
150                                         /* only one face attached to that edge */
151                                         /* an edge without another attached- the weight on this is undefined */
152                                         copy_v3_v3(edge_normal, face_nors[edge_ref->f1]);
153                                 }
154                                 add_v3_v3(r_vert_nors[ed->v1], edge_normal);
155                                 add_v3_v3(r_vert_nors[ed->v2], edge_normal);
156                         }
157                 }
158                 MEM_freeN(edge_ref_array);
159         }
160
161         /* normalize vertex normals and assign */
162         for (i = 0; i < numVerts; i++, mv++) {
163                 if (normalize_v3(r_vert_nors[i]) == 0.0f) {
164                         normal_short_to_float_v3(r_vert_nors[i], mv->no);
165                 }
166         }
167 }
168
169 static void initData(ModifierData *md)
170 {
171         SolidifyModifierData *smd = (SolidifyModifierData *) md;
172         smd->offset = 0.01f;
173         smd->offset_fac = -1.0f;
174         smd->flag = MOD_SOLIDIFY_RIM;
175 }
176
177 static void copyData(ModifierData *md, ModifierData *target)
178 {
179 #if 0
180         SolidifyModifierData *smd = (SolidifyModifierData *) md;
181         SolidifyModifierData *tsmd = (SolidifyModifierData *) target;
182 #endif
183         modifier_copyData_generic(md, target);
184 }
185
186 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
187 {
188         SolidifyModifierData *smd = (SolidifyModifierData *) md;
189         CustomDataMask dataMask = 0;
190
191         /* ask for vertexgroups if we need them */
192         if (smd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
193
194         return dataMask;
195 }
196
197 /* specific function for solidify - define locally */
198 BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
199 {
200         r[0] += (float)a[0] * f;
201         r[1] += (float)a[1] * f;
202         r[2] += (float)a[2] * f;
203 }
204
205 static DerivedMesh *applyModifier(
206         ModifierData *md, Object *ob,
207         DerivedMesh *dm,
208         ModifierApplyFlag UNUSED(flag))
209 {
210         unsigned int i;
211         DerivedMesh *result;
212         const SolidifyModifierData *smd = (SolidifyModifierData *) md;
213
214         MVert *mv, *mvert, *orig_mvert;
215         MEdge *ed, *medge, *orig_medge;
216         MLoop *ml, *mloop, *orig_mloop;
217         MPoly *mp, *mpoly, *orig_mpoly;
218         const unsigned int numVerts = (unsigned int)dm->getNumVerts(dm);
219         const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
220         const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm);
221         const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm);
222         unsigned int newLoops = 0, newFaces = 0, newEdges = 0;
223
224         /* only use material offsets if we have 2 or more materials  */
225         const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0;
226         const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0;
227         const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0;
228
229         /* use for edges */
230         /* over-alloc new_vert_arr, old_vert_arr */
231         unsigned int *new_vert_arr = NULL;
232         STACK_DECLARE(new_vert_arr);
233
234         unsigned int *new_edge_arr = NULL;
235         STACK_DECLARE(new_edge_arr);
236
237         unsigned int *old_vert_arr = MEM_callocN(sizeof(*old_vert_arr) * (size_t)numVerts, "old_vert_arr in solidify");
238
239         unsigned int *edge_users = NULL;
240         char *edge_order = NULL;
241
242         float (*vert_nors)[3] = NULL;
243         float (*face_nors)[3] = NULL;
244
245         const bool need_face_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || (smd->flag & MOD_SOLIDIFY_EVEN);
246
247         const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
248         const float ofs_new  = smd->offset + ofs_orig;
249         const float offset_fac_vg = smd->offset_fac_vg;
250         const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
251         const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
252         const bool do_clamp = (smd->offset_clamp != 0.0f);
253
254         /* weights */
255         MDeformVert *dvert, *dv = NULL;
256         const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
257         int defgrp_index;
258
259         modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
260
261         orig_mvert = dm->getVertArray(dm);
262         orig_medge = dm->getEdgeArray(dm);
263         orig_mloop = dm->getLoopArray(dm);
264         orig_mpoly = dm->getPolyArray(dm);
265
266         if (need_face_normals) {
267                 /* calculate only face normals */
268                 face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__);
269                 BKE_mesh_calc_normals_poly(
270                             orig_mvert, (int)numVerts,
271                             orig_mloop, orig_mpoly,
272                             (int)numLoops, (int)numFaces,
273                             face_nors, true);
274         }
275
276         STACK_INIT(new_vert_arr);
277         STACK_INIT(new_edge_arr);
278
279         if (smd->flag & MOD_SOLIDIFY_RIM) {
280                 unsigned int eidx;
281
282 #define INVALID_UNUSED ((unsigned int)-1)
283 #define INVALID_PAIR ((unsigned int)-2)
284
285                 new_vert_arr = MEM_mallocN(sizeof(*new_vert_arr) * (size_t)(numVerts * 2), __func__);
286                 new_edge_arr = MEM_mallocN(sizeof(*new_edge_arr) * (size_t)((numEdges * 2) + numVerts), __func__);
287
288                 edge_users = MEM_mallocN(sizeof(*edge_users) * (size_t)numEdges, "solid_mod edges");
289                 edge_order = MEM_mallocN(sizeof(*edge_order) * (size_t)numEdges, "solid_mod eorder");
290
291                 for (i = 0, mv = orig_mvert; i < numVerts; i++, mv++) {
292                         mv->flag &= ~ME_VERT_TMP_TAG;
293                 }
294
295                 /* save doing 2 loops here... */
296 #if 0
297                 fill_vn_i(edge_users, numEdges, INVALID_UNUSED);
298 #endif
299
300                 for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
301                         edge_users[eidx] = INVALID_UNUSED;
302                 }
303
304                 for (i = 0, mp = orig_mpoly; i < numFaces; i++, mp++) {
305                         MLoop *ml_prev;
306                         int j;
307
308                         ml = orig_mloop + mp->loopstart;
309                         ml_prev = ml + (mp->totloop - 1);
310
311                         for (j = 0; j < mp->totloop; j++, ml++) {
312                                 /* add edge user */
313                                 eidx = ml_prev->e;
314                                 if (edge_users[eidx] == INVALID_UNUSED) {
315                                         ed = orig_medge + eidx;
316                                         BLI_assert(ELEM(ml_prev->v,    ed->v1, ed->v2) &&
317                                                    ELEM(ml->v, ed->v1, ed->v2));
318                                         edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numFaces);
319                                         edge_order[eidx] = j;
320                                 }
321                                 else {
322                                         edge_users[eidx] = INVALID_PAIR;
323                                 }
324                                 ml_prev = ml;
325                         }
326                 }
327
328                 for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
329                         if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) {
330                                 orig_mvert[ed->v1].flag |= ME_VERT_TMP_TAG;
331                                 orig_mvert[ed->v2].flag |= ME_VERT_TMP_TAG;
332                                 STACK_PUSH(new_edge_arr, eidx);
333                                 newFaces++;
334                                 newLoops += 4;
335                         }
336                 }
337
338 #undef INVALID_UNUSED
339 #undef INVALID_PAIR
340
341                 for (i = 0, mv = orig_mvert; i < numVerts; i++, mv++) {
342                         if (mv->flag & ME_VERT_TMP_TAG) {
343                                 old_vert_arr[i] = STACK_SIZE(new_vert_arr);
344                                 STACK_PUSH(new_vert_arr, i);
345                                 newEdges++;
346
347                                 mv->flag &= ~ME_VERT_TMP_TAG;
348                         }
349                 }
350         }
351
352         if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
353                 vert_nors = MEM_callocN(sizeof(float) * (size_t)numVerts * 3, "mod_solid_vno_hq");
354                 dm_calc_normal(dm, face_nors, vert_nors);
355         }
356
357         result = CDDM_from_template(dm,
358                                     (int)(numVerts * 2),
359                                     (int)((numEdges * 2) + newEdges), 0,
360                                     (int)((numLoops * 2) + newLoops),
361                                     (int)((numFaces * 2) + newFaces));
362
363         mpoly = CDDM_get_polys(result);
364         mloop = CDDM_get_loops(result);
365         medge = CDDM_get_edges(result);
366         mvert = CDDM_get_verts(result);
367
368         DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
369         DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges);
370
371         DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
372         DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts);
373
374         DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
375         DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops);
376
377         DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
378         DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces);
379
380         /* flip normals */
381         mp = mpoly + numFaces;
382         for (i = 0; i < dm->numPolyData; i++, mp++) {
383                 MLoop *ml2;
384                 unsigned int e;
385                 int j;
386
387                 ml2 = mloop + mp->loopstart + dm->numLoopData;
388                 for (j = 0; j < mp->totloop; j++) {
389                         CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
390                                              mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1);
391                 }
392
393                 if (mat_ofs) {
394                         mp->mat_nr += mat_ofs;
395                         CLAMP(mp->mat_nr, 0, mat_nr_max);
396                 }
397
398                 e = ml2[0].e;
399                 for (j = 0; j < mp->totloop - 1; j++) {
400                         ml2[j].e = ml2[j + 1].e;
401                 }
402                 ml2[mp->totloop - 1].e = e;
403
404                 mp->loopstart += dm->numLoopData;
405
406                 for (j = 0; j < mp->totloop; j++) {
407                         ml2[j].e += numEdges;
408                         ml2[j].v += numVerts;
409                 }
410         }
411
412         for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) {
413                 ed->v1 += numVerts;
414                 ed->v2 += numVerts;
415         }
416
417         /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */
418         if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
419                 /* no even thickness, very simple */
420                 float scalar_short;
421                 float scalar_short_vgroup;
422
423                 /* for clamping */
424                 float *vert_lens = NULL;
425                 const float offset    = fabsf(smd->offset) * smd->offset_clamp;
426                 const float offset_sq = offset * offset;
427
428                 if (do_clamp) {
429                         vert_lens = MEM_callocN(sizeof(float) * numVerts, "vert_lens");
430                         fill_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
431                         for (i = 0; i < numEdges; i++) {
432                                 const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
433                                 vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len);
434                                 vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len);
435                         }
436                 }
437
438                 if (ofs_new != 0.0f) {
439                         scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
440                         mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? numVerts : 0);
441                         dv = dvert;
442                         for (i = 0; i < numVerts; i++, mv++) {
443                                 if (dv) {
444                                         if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
445                                         else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
446                                         scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
447                                         dv++;
448                                 }
449                                 if (do_clamp) {
450                                         /* always reset becaise we may have set before */
451                                         if (dv == NULL) {
452                                                 scalar_short_vgroup = scalar_short;
453                                         }
454                                         if (vert_lens[i] < offset_sq) {
455                                                 float scalar = sqrtf(vert_lens[i]) / offset;
456                                                 scalar_short_vgroup *= scalar;
457                                         }
458                                 }
459                                 madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
460                         }
461                 }
462
463                 if (ofs_orig != 0.0f) {
464                         scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
465                         mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? 0 : numVerts); /* as above but swapped */
466                         dv = dvert;
467                         for (i = 0; i < numVerts; i++, mv++) {
468                                 if (dv) {
469                                         if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
470                                         else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
471                                         scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
472                                         dv++;
473                                 }
474                                 if (do_clamp) {
475                                         /* always reset becaise we may have set before */
476                                         if (dv == NULL) {
477                                                 scalar_short_vgroup = scalar_short;
478                                         }
479                                         if (vert_lens[i] < offset_sq) {
480                                                 float scalar = sqrtf(vert_lens[i]) / offset;
481                                                 scalar_short_vgroup *= scalar;
482                                         }
483                                 }
484                                 madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
485                         }
486                 }
487
488                 if (do_clamp) {
489                         MEM_freeN(vert_lens);
490                 }
491         }
492         else {
493 #ifdef USE_NONMANIFOLD_WORKAROUND
494                 const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0;
495 #endif
496                 /* same as EM_solidify() in editmesh_lib.c */
497                 float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
498                 float *vert_accum = vert_angles + numVerts;
499                 unsigned int vidx;
500
501                 if (vert_nors == NULL) {
502                         vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
503                         for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
504                                 normal_short_to_float_v3(vert_nors[i], mv->no);
505                         }
506                 }
507
508                 for (i = 0, mp = mpoly; i < numFaces; i++, mp++) {
509                         /* #BKE_mesh_calc_poly_angles logic is inlined here */
510                         float nor_prev[3];
511                         float nor_next[3];
512
513                         int i_curr = mp->totloop - 1;
514                         int i_next = 0;
515
516                         ml = &mloop[mp->loopstart];
517
518                         sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co);
519                         normalize_v3(nor_prev);
520
521                         while (i_next < mp->totloop) {
522                                 float angle;
523                                 sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co);
524                                 normalize_v3(nor_next);
525                                 angle = angle_normalized_v3v3(nor_prev, nor_next);
526
527
528                                 /* --- not related to angle calc --- */
529                                 if (angle < FLT_EPSILON) {
530                                         angle = FLT_EPSILON;
531                                 }
532
533                                 vidx = ml[i_curr].v;
534                                 vert_accum[vidx] += angle;
535
536 #ifdef USE_NONMANIFOLD_WORKAROUND
537                                 /* skip 3+ face user edges */
538                                 if ((check_non_manifold == false) ||
539                                     LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) &&
540                                            ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0)))
541                                 {
542                                         vert_angles[vidx] += shell_angle_to_dist(angle_normalized_v3v3(vert_nors[vidx], face_nors[i])) * angle;
543                                 }
544                                 else {
545                                         vert_angles[vidx] += angle;
546                                 }
547 #else
548                                 vert_angles[vidx] += shell_angle_to_dist(angle_normalized_v3v3(vert_nors[vidx], face_nors[i])) * angle;
549 #endif
550                                 /* --- end non-angle-calc section --- */
551
552
553                                 /* step */
554                                 copy_v3_v3(nor_prev, nor_next);
555                                 i_curr = i_next;
556                                 i_next++;
557                         }
558                 }
559
560                 /* vertex group support */
561                 if (dvert) {
562                         float scalar;
563
564                         dv = dvert;
565                         if (defgrp_invert) {
566                                 for (i = 0; i < numVerts; i++, dv++) {
567                                         scalar = 1.0f - defvert_find_weight(dv, defgrp_index);
568                                         scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
569                                         vert_angles[i] *= scalar;
570                                 }
571                         }
572                         else {
573                                 for (i = 0; i < numVerts; i++, dv++) {
574                                         scalar = defvert_find_weight(dv, defgrp_index);
575                                         scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
576                                         vert_angles[i] *= scalar;
577                                 }
578                         }
579                 }
580
581                 if (do_clamp) {
582                         float *vert_lens = MEM_callocN(sizeof(float) * numVerts, "vert_lens");
583                         const float offset    = fabsf(smd->offset) * smd->offset_clamp;
584                         const float offset_sq = offset * offset;
585                         fill_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
586                         for (i = 0; i < numEdges; i++) {
587                                 const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
588                                 vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len);
589                                 vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len);
590                         }
591                         for (i = 0; i < numVerts; i++) {
592                                 if (vert_lens[i] < offset_sq) {
593                                         float scalar = sqrtf(vert_lens[i]) / offset;
594                                         vert_angles[i] *= scalar;
595                                 }
596                         }
597                         MEM_freeN(vert_lens);
598                 }
599
600                 if (ofs_new) {
601                         mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? numVerts : 0);
602
603                         for (i = 0; i < numVerts; i++, mv++) {
604                                 if (vert_accum[i]) { /* zero if unselected */
605                                         madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i]));
606                                 }
607                         }
608                 }
609
610                 if (ofs_orig) {
611                         /* same as above but swapped, intentional use of 'ofs_new' */
612                         mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? 0 : numVerts);
613
614                         for (i = 0; i < numVerts; i++, mv++) {
615                                 if (vert_accum[i]) { /* zero if unselected */
616                                         madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i]));
617                                 }
618                         }
619                 }
620
621                 MEM_freeN(vert_angles);
622         }
623
624         if (vert_nors)
625                 MEM_freeN(vert_nors);
626
627         /* must recalculate normals with vgroups since they can displace unevenly [#26888] */
628         if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
629                 result->dirty |= DM_DIRTY_NORMALS;
630         }
631         else {
632                 /* flip vertex normals for copied verts */
633                 mv = mvert + numVerts;
634                 for (i = 0; i < numVerts; i++, mv++) {
635                         negate_v3_short(mv->no);
636                 }
637         }
638
639         if (smd->flag & MOD_SOLIDIFY_RIM) {
640
641                 /* bugger, need to re-calculate the normals for the new edge faces.
642                  * This could be done in many ways, but probably the quickest way
643                  * is to calculate the average normals for side faces only.
644                  * Then blend them with the normals of the edge verts.
645                  *
646                  * at the moment its easiest to allocate an entire array for every vertex,
647                  * even though we only need edge verts - campbell
648                  */
649
650 #define SOLIDIFY_SIDE_NORMALS
651
652 #ifdef SOLIDIFY_SIDE_NORMALS
653                 const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS);
654                 /* annoying to allocate these since we only need the edge verts, */
655                 float (*edge_vert_nos)[3] = do_side_normals ? MEM_callocN(sizeof(float) * numVerts * 3, __func__) : NULL;
656                 float nor[3];
657 #endif
658                 const unsigned char crease_rim = smd->crease_rim * 255.0f;
659                 const unsigned char crease_outer = smd->crease_outer * 255.0f;
660                 const unsigned char crease_inner = smd->crease_inner * 255.0f;
661
662                 int *origindex_edge;
663                 int *orig_ed;
664                 unsigned int j;
665
666                 if (crease_rim || crease_outer || crease_inner) {
667                         result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
668                 }
669
670                 /* add faces & edges */
671                 origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX);
672                 ed = &medge[numEdges * 2];
673                 orig_ed = &origindex_edge[numEdges * 2];
674                 for (i = 0; i < newEdges; i++, ed++, orig_ed++) {
675                         ed->v1 = new_vert_arr[i];
676                         ed->v2 = new_vert_arr[i] + numVerts;
677                         ed->flag |= ME_EDGEDRAW;
678
679                         *orig_ed = ORIGINDEX_NONE;
680
681                         if (crease_rim) {
682                                 ed->crease = crease_rim;
683                         }
684                 }
685
686                 /* faces */
687                 mp = mpoly + (numFaces * 2);
688                 ml = mloop + (numLoops * 2);
689                 j = 0;
690                 for (i = 0; i < newFaces; i++, mp++) {
691                         unsigned int eidx = new_edge_arr[i];
692                         unsigned int fidx = edge_users[eidx];
693                         int k1, k2;
694                         bool flip;
695
696                         if (fidx >= numFaces) {
697                                 fidx -= numFaces;
698                                 flip = true;
699                         }
700                         else {
701                                 flip = false;
702                         }
703
704                         ed = medge + eidx;
705
706                         /* copy most of the face settings */
707                         DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * 2) + i), 1);
708                         mp->loopstart = (int)(j + numLoops * 2);
709                         mp->flag = mpoly[fidx].flag;
710
711                         /* notice we use 'mp->totloop' which is later overwritten,
712                          * we could lookup the original face but theres no point since this is a copy
713                          * and will have the same value, just take care when changing order of assignment */
714                         k1 = mpoly[fidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop);  /* prev loop */
715                         k2 = mpoly[fidx].loopstart +   (edge_order[eidx]);
716
717                         mp->totloop = 4;
718
719                         CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)(numLoops * 2 + j + 0), 1);
720                         CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)(numLoops * 2 + j + 1), 1);
721                         CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)(numLoops * 2 + j + 2), 1);
722                         CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)(numLoops * 2 + j + 3), 1);
723
724                         if (flip == FALSE) {
725                                 ml[j].v = ed->v1;
726                                 ml[j++].e = eidx;
727
728                                 ml[j].v = ed->v2;
729                                 ml[j++].e = numEdges * 2 + old_vert_arr[ed->v2];
730
731                                 ml[j].v = ed->v2 + numVerts;
732                                 ml[j++].e = eidx + numEdges;
733
734                                 ml[j].v = ed->v1 + numVerts;
735                                 ml[j++].e = numEdges * 2 + old_vert_arr[ed->v1];
736                         }
737                         else {
738                                 ml[j].v = ed->v2;
739                                 ml[j++].e = eidx;
740
741                                 ml[j].v = ed->v1;
742                                 ml[j++].e = numEdges * 2 + old_vert_arr[ed->v1];
743
744                                 ml[j].v = ed->v1 + numVerts;
745                                 ml[j++].e = eidx + numEdges;
746
747                                 ml[j].v = ed->v2 + numVerts;
748                                 ml[j++].e = numEdges * 2 + old_vert_arr[ed->v2];
749                         }
750
751                         origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE;
752                         origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE;
753
754                         /* use the next material index if option enabled */
755                         if (mat_ofs_rim) {
756                                 mp->mat_nr += mat_ofs_rim;
757                                 CLAMP(mp->mat_nr, 0, mat_nr_max);
758                         }
759                         if (crease_outer) {
760                                 /* crease += crease_outer; without wrapping */
761                                 unsigned char *cr = (unsigned char *)&(ed->crease);
762                                 int tcr = *cr + crease_outer;
763                                 *cr = tcr > 255 ? 255 : tcr;
764                         }
765
766                         if (crease_inner) {
767                                 /* crease += crease_inner; without wrapping */
768                                 unsigned char *cr = (unsigned char *)&(medge[numEdges + eidx].crease);
769                                 int tcr = *cr + crease_inner;
770                                 *cr = tcr > 255 ? 255 : tcr;
771                         }
772
773 #ifdef SOLIDIFY_SIDE_NORMALS
774                         if (do_side_normals) {
775                                 normal_quad_v3(nor,
776                                                mvert[ml[j - 4].v].co,
777                                                mvert[ml[j - 3].v].co,
778                                                mvert[ml[j - 2].v].co,
779                                                mvert[ml[j - 1].v].co);
780
781                                 add_v3_v3(edge_vert_nos[ed->v1], nor);
782                                 add_v3_v3(edge_vert_nos[ed->v2], nor);
783                         }
784 #endif
785                 }
786
787 #ifdef SOLIDIFY_SIDE_NORMALS
788                 if (do_side_normals) {
789                         ed = medge + (numEdges * 2);
790                         for (i = 0; i < newEdges; i++, ed++) {
791                                 float nor_cpy[3];
792                                 short *nor_short;
793                                 int k;
794
795                                 /* note, only the first vertex (lower half of the index) is calculated */
796                                 normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]);
797
798                                 for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
799                                         nor_short = mvert[*(&ed->v1 + k)].no;
800                                         normal_short_to_float_v3(nor, nor_short);
801                                         add_v3_v3(nor, nor_cpy);
802                                         normalize_v3(nor);
803                                         normal_float_to_short_v3(nor_short, nor);
804                                 }
805                         }
806
807                         MEM_freeN(edge_vert_nos);
808                 }
809 #endif
810
811                 MEM_freeN(new_vert_arr);
812                 MEM_freeN(new_edge_arr);
813
814                 MEM_freeN(edge_users);
815                 MEM_freeN(edge_order);
816         }
817
818         STACK_FREE(new_vert_arr);
819         STACK_FREE(new_edge_arr);
820
821         if (old_vert_arr)
822                 MEM_freeN(old_vert_arr);
823
824         if (face_nors)
825                 MEM_freeN(face_nors);
826
827         if (numFaces == 0 && numEdges != 0) {
828                 modifier_setError(md, "Faces needed for useful output");
829         }
830
831         return result;
832 }
833
834 #undef SOLIDIFY_SIDE_NORMALS
835
836 static bool dependsOnNormals(ModifierData *UNUSED(md))
837 {
838         /* even when we calculate our own normals,
839          * the vertex normals are used as a fallback */
840         return true;
841 }
842
843 ModifierTypeInfo modifierType_Solidify = {
844         /* name */              "Solidify",
845         /* structName */        "SolidifyModifierData",
846         /* structSize */        sizeof(SolidifyModifierData),
847         /* type */              eModifierTypeType_Constructive,
848
849         /* flags */             eModifierTypeFlag_AcceptsMesh |
850                                 eModifierTypeFlag_AcceptsCVs |
851                                 eModifierTypeFlag_SupportsMapping |
852                                 eModifierTypeFlag_SupportsEditmode |
853                                 eModifierTypeFlag_EnableInEditmode,
854
855         /* copyData */          copyData,
856         /* deformVerts */       NULL,
857         /* deformMatrices */    NULL,
858         /* deformVertsEM */     NULL,
859         /* deformMatricesEM */  NULL,
860         /* applyModifier */     applyModifier,
861         /* applyModifierEM */   NULL,
862         /* initData */          initData,
863         /* requiredDataMask */  requiredDataMask,
864         /* freeData */          NULL,
865         /* isDisabled */        NULL,
866         /* updateDepgraph */    NULL,
867         /* dependsOnTime */     NULL,
868         /* dependsOnNormals */  dependsOnNormals,
869         /* foreachObjectLink */ NULL,
870         /* foreachIDLink */     NULL,
871         /* foreachTexLink */    NULL,
872 };