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