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