- add BM_NGON_STACK_SIZE define to use wherever ngon stack arrays are used.
[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): Daniel Dunbar
22  *                 Ton Roosendaal,
23  *                 Ben Batt,
24  *                 Brecht Van Lommel,
25  *                 Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  *
29  */
30
31 /** \file blender/modifiers/intern/MOD_solidify.c
32  *  \ingroup modifiers
33  */
34
35
36 #include "DNA_meshdata_types.h"
37
38 #include "BLI_utildefines.h"
39 #include "BLI_math.h"
40 #include "BLI_edgehash.h"
41 #include "BLI_array.h"
42 #include "BLI_smallhash.h"
43 #include "BLI_string.h"
44
45 #include "BKE_cdderivedmesh.h"
46 #include "BKE_mesh.h"
47 #include "BKE_particle.h"
48 #include "BKE_deform.h"
49
50
51 #include "MOD_modifiertypes.h"
52 #include "MOD_util.h"
53
54 #include "MEM_guardedalloc.h"
55
56 typedef struct EdgeFaceRef {
57         int f1; /* init as -1 */
58         int f2;
59 } EdgeFaceRef;
60
61 static void dm_calc_normal(DerivedMesh *dm, float (*temp_nors)[3])
62 {
63         int i, numVerts, numEdges, numFaces;
64         MPoly *mpoly, *mp;
65         MLoop *mloop, *ml;
66         MVert *mvert, *mv;
67
68         float (*face_nors)[3];
69         float *f_no;
70         int calc_face_nors= 0;
71
72         numVerts = dm->getNumVerts(dm);
73         numEdges = dm->getNumEdges(dm);
74         numFaces = dm->getNumFaces(dm);
75         mpoly = CDDM_get_polys(dm);
76         mvert = dm->getVertArray(dm);
77         mloop = CDDM_get_loops(dm);
78         
79         /* we don't want to overwrite any referenced layers */
80
81         /*
82         Dosnt work here!
83         mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
84         cddm->mvert = mv;
85         */
86
87         face_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
88         if(!face_nors) {
89                 calc_face_nors = 1;
90                 face_nors = CustomData_add_layer(&dm->polyData, CD_NORMAL, CD_CALLOC, NULL, numFaces);
91         }
92
93         mv = mvert;
94         mp = mpoly;
95
96         {
97                 EdgeHash *edge_hash = BLI_edgehash_new();
98                 EdgeHashIterator *edge_iter;
99                 int edge_ref_count = 0;
100                 int ed_v1, ed_v2; /* use when getting the key */
101                 EdgeFaceRef *edge_ref_array = MEM_callocN(numEdges * sizeof(EdgeFaceRef), "Edge Connectivity");
102                 EdgeFaceRef *edge_ref;
103                 float edge_normal[3];
104
105                 /* This function adds an edge hash if its not there, and adds the face index */
106 #define NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(EDV1, EDV2); \
107                                 edge_ref = (EdgeFaceRef *)BLI_edgehash_lookup(edge_hash, EDV1, EDV2); \
108                                 if (!edge_ref) { \
109                                         edge_ref = &edge_ref_array[edge_ref_count]; edge_ref_count++; \
110                                         edge_ref->f1=i; \
111                                         edge_ref->f2=-1; \
112                                         BLI_edgehash_insert(edge_hash, EDV1, EDV2, edge_ref); \
113                                 } else { \
114                                         edge_ref->f2=i; \
115                                 }
116
117                 for(i = 0; i < numFaces; i++, mp++) {
118                         int j;
119                         
120                         f_no = face_nors[i];
121                         if(calc_face_nors)
122                                 mesh_calc_poly_normal(mp, mloop+mp->loopstart, mvert, f_no);
123
124                         ml = mloop + mp->loopstart;
125                         for (j=0; j<mp->totloop; j++) {
126                                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(ml[j].v, ml[(j+1)%mp->totloop].v);
127                         }
128                 }
129
130                 for(edge_iter = BLI_edgehashIterator_new(edge_hash); !BLI_edgehashIterator_isDone(edge_iter); BLI_edgehashIterator_step(edge_iter)) {
131                         /* Get the edge vert indices, and edge value (the face indices that use it)*/
132                         BLI_edgehashIterator_getKey(edge_iter, (int*)&ed_v1, (int*)&ed_v2);
133                         edge_ref = BLI_edgehashIterator_getValue(edge_iter);
134
135                         if (edge_ref->f2 != -1) {
136                                 /* We have 2 faces using this edge, calculate the edges normal
137                                  * using the angle between the 2 faces as a weighting */
138                                 add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
139                                 normalize_v3(edge_normal);
140                                 mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
141                         } else {
142                                 /* only one face attached to that edge */
143                                 /* an edge without another attached- the weight on this is
144                                  * undefined, M_PI/2 is 90d in radians and that seems good enough */
145                                 mul_v3_v3fl(edge_normal, face_nors[edge_ref->f1], M_PI/2);
146                         }
147                         add_v3_v3(temp_nors[ed_v1], edge_normal);
148                         add_v3_v3(temp_nors[ed_v2], edge_normal);
149                 }
150                 BLI_edgehashIterator_free(edge_iter);
151                 BLI_edgehash_free(edge_hash, NULL);
152                 MEM_freeN(edge_ref_array);
153         }
154
155         /* normalize vertex normals and assign */
156         for(i = 0; i < numVerts; i++, mv++) {
157                 if(normalize_v3(temp_nors[i]) == 0.0f) {
158                         normal_short_to_float_v3(temp_nors[i], mv->no);
159                 }
160         }
161 }
162  
163 static void initData(ModifierData *md)
164 {
165         SolidifyModifierData *smd = (SolidifyModifierData*) md;
166         smd->offset = 0.01f;
167         smd->offset_fac = -1.0f;
168         smd->flag = MOD_SOLIDIFY_RIM;
169 }
170  
171 static void copyData(ModifierData *md, ModifierData *target)
172 {
173         SolidifyModifierData *smd = (SolidifyModifierData*) md;
174         SolidifyModifierData *tsmd = (SolidifyModifierData*) target;
175         tsmd->offset = smd->offset;
176         tsmd->offset_fac = smd->offset_fac;
177         tsmd->crease_inner = smd->crease_inner;
178         tsmd->crease_outer = smd->crease_outer;
179         tsmd->crease_rim = smd->crease_rim;
180         tsmd->flag = smd->flag;
181         BLI_strncpy(tsmd->defgrp_name, smd->defgrp_name, sizeof(tsmd->defgrp_name));
182 }
183
184 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
185 {
186         SolidifyModifierData *smd = (SolidifyModifierData*) md;
187         CustomDataMask dataMask = 0;
188
189         /* ask for vertexgroups if we need them */
190         if(smd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
191
192         return dataMask;
193 }
194
195
196 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, 
197                                                 DerivedMesh *dm,
198                                                 int UNUSED(useRenderParams),
199                                                 int UNUSED(isFinalCalc))
200 {
201         int i;
202         DerivedMesh *result, *odm = dm;
203         const SolidifyModifierData *smd = (SolidifyModifierData*) md;
204
205         MVert *mv, *mvert, *orig_mvert;
206         MEdge *ed, *medge, *orig_medge;
207         MLoop *ml, *mloop, *orig_mloop;
208         MPoly *mp, *mpoly, *orig_mpoly;
209         const int numVerts = dm->getNumVerts(dm);
210         const int numEdges = dm->getNumEdges(dm);
211         const int numFaces = dm->getNumFaces(dm);
212         int numLoops=0, newLoops=0, newFaces=0, newEdges=0;
213         int j;
214         
215         /* only use material offsets if we have 2 or more materials  */
216         const short mat_nr_max= ob->totcol > 1 ? ob->totcol - 1 : 0;
217         const short mat_ofs= mat_nr_max ? smd->mat_ofs : 0;
218         /* const short mat_ofs_rim= mat_nr_max ? smd->mat_ofs_rim : 0; */ /* UNUSED */
219
220         /* use for edges */
221         int *new_vert_arr= NULL;
222         BLI_array_declare(new_vert_arr);
223         int *new_edge_arr= NULL;
224         BLI_array_declare(new_edge_arr);
225         int *old_vert_arr = MEM_callocN(sizeof(int)*numVerts, "old_vert_arr in solidify");
226
227         int *edge_users= NULL;
228         char *edge_order= NULL;
229         int *edge_origIndex;
230         
231         float (*vert_nors)[3]= NULL;
232
233         const float ofs_orig=                           - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
234         const float ofs_new= smd->offset        - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
235         const float offset_fac_vg= smd->offset_fac_vg;
236         const float offset_fac_vg_inv= 1.0f - smd->offset_fac_vg;
237
238         /* weights */
239         MDeformVert *dvert, *dv= NULL;
240         const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
241         int defgrp_index;
242
243         modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
244         
245         if (!CDDM_Check(dm)) {
246                 DerivedMesh *dm2 = CDDM_copy(dm, 0);
247                 dm = dm2;
248         }
249         
250         numLoops = dm->numLoopData;
251         newLoops = 0;
252         
253         orig_mvert = CDDM_get_verts(dm);
254         orig_medge = CDDM_get_edges(dm);
255         orig_mloop = CDDM_get_loops(dm);
256         orig_mpoly = CDDM_get_polys(dm);
257
258         if(smd->flag & MOD_SOLIDIFY_RIM) {
259                 EdgeHash *edgehash = BLI_edgehash_new();
260                 EdgeHashIterator *ehi;
261                 int v1, v2;
262                 int eidx;
263
264                 for(i=0, mv=orig_mvert; i<numVerts; i++, mv++) {
265                         mv->flag &= ~ME_VERT_TMP_TAG;
266                 }
267
268                 for(i=0, ed=orig_medge; i<numEdges; i++, ed++) {
269                         BLI_edgehash_insert(edgehash, ed->v1, ed->v2, SET_INT_IN_POINTER(i));
270                 }
271
272 #define INVALID_UNUSED -1
273 #define INVALID_PAIR -2
274
275 #define ADD_EDGE_USER(_v1, _v2, edge_ord) \
276                 eidx= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edgehash, _v1, _v2)); \
277                 if(edge_users[eidx] == INVALID_UNUSED) { \
278                         ed= orig_medge + eidx; \
279                         edge_users[eidx]= (_v1 < _v2) == (ed->v1 < ed->v2) ? i:(i+numFaces); \
280                         edge_order[eidx]= edge_ord; \
281                 } else { \
282                         edge_users[eidx]= INVALID_PAIR; \
283                 } \
284
285
286                 edge_users= MEM_mallocN(sizeof(int) * numEdges, "solid_mod edges");
287                 edge_order= MEM_mallocN(sizeof(char) * numEdges, "solid_mod eorder");
288                 memset(edge_users, INVALID_UNUSED, sizeof(int) * numEdges);
289                 
290                 for (i=0, mp=orig_mpoly; i<numFaces; i++, mp++) {
291                         MLoop *ml;
292                         
293                         for (ml=orig_mloop + mp->loopstart, j=0; j<mp->totloop; ml++, j++) {
294                                 MLoop *ml2 = orig_mloop + mp->loopstart + (j+1)%mp->totloop;
295                                 ADD_EDGE_USER(ml->v, ml2->v, j);
296                         }       
297                 }
298
299 #undef ADD_EDGE_USER
300 #undef INVALID_UNUSED
301 #undef INVALID_PAIR
302
303                 ehi= BLI_edgehashIterator_new(edgehash);
304                 for(; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
305                         eidx= GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
306                         if(edge_users[eidx] >= 0) {
307                                 BLI_edgehashIterator_getKey(ehi, &v1, &v2);
308                                 orig_mvert[v1].flag |= ME_VERT_TMP_TAG;
309                                 orig_mvert[v2].flag |= ME_VERT_TMP_TAG;
310                                 BLI_array_append(new_edge_arr, eidx);
311                                 newFaces++;
312                                 newLoops += 4;
313                         }
314                 }
315                 BLI_edgehashIterator_free(ehi);
316
317                 for(i=0, mv=orig_mvert; i<numVerts; i++, mv++) {
318                         if(mv->flag & ME_VERT_TMP_TAG) {
319                                 old_vert_arr[i] = BLI_array_count(new_vert_arr);
320                                 BLI_array_append(new_vert_arr, i);
321                                 newEdges++;
322
323                                 mv->flag &= ~ME_VERT_TMP_TAG;
324                         }
325                 }
326
327                 BLI_edgehash_free(edgehash, NULL);
328         }
329
330         if(smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
331                 vert_nors= MEM_callocN(sizeof(float) * numVerts * 3, "mod_solid_vno_hq");
332                 dm_calc_normal(dm, vert_nors);
333         }
334
335         result = CDDM_from_template(dm, numVerts * 2, (numEdges * 2) + newEdges, 0, (numLoops*2) + newLoops, (numFaces * 2) + newFaces);
336
337         mpoly = CDDM_get_polys(result);
338         mloop = CDDM_get_loops(result);
339         medge = CDDM_get_edges(result);
340         mvert = CDDM_get_verts(result);
341
342         DM_copy_edge_data(dm, result, 0, 0, numEdges);
343         DM_copy_edge_data(dm, result, 0, numEdges, numEdges);
344
345         DM_copy_vert_data(dm, result, 0, 0, numVerts);
346         DM_copy_vert_data(dm, result, 0, numVerts, numVerts);
347
348         DM_copy_loop_data(dm, result, 0, 0, numLoops);
349         DM_copy_loop_data(dm, result, 0, numLoops, numLoops);
350
351         DM_copy_face_data(dm, result, 0, 0, numFaces);
352         DM_copy_face_data(dm, result, 0, numFaces, numFaces);
353         
354         /*flip normals*/
355         mp = mpoly + numFaces;
356         for (i=0; i<dm->numPolyData; i++, mp++) {
357                 MLoop *ml2;
358                 int e;
359
360                 ml2 = mloop + mp->loopstart + dm->numLoopData;
361                 for (j=0; j<mp->totloop; j++) {
362                         CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart+j, 
363                                              mp->loopstart+(mp->totloop-j-1)+dm->numLoopData, 1);
364
365                         if(mat_ofs) {
366                                 mp->mat_nr += mat_ofs;
367                                 CLAMP(mp->mat_nr, 0, mat_nr_max);
368                         }
369                 }
370                 
371                 e = ml2[0].e;
372                 for (j=0; j<mp->totloop-1; j++) {
373                         ml2[j].e = ml2[j+1].e;
374                 }
375                 ml2[mp->totloop-1].e = e;
376                 
377                 mp->loopstart += dm->numLoopData;
378                 
379                 for (j=0; j<mp->totloop; j++) {
380                         ml2[j].e += numEdges;
381                         ml2[j].v += numVerts;
382                 }
383         }
384
385         for(i=0, ed=medge+numEdges; i<numEdges; i++, ed++) {
386                 ed->v1 += numVerts;
387                 ed->v2 += numVerts;
388         }
389
390         /* note, copied vertex layers dont have flipped normals yet. do this after applying offset */
391         if((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
392                 /* no even thickness, very simple */
393                 float scalar_short;
394                 float scalar_short_vgroup;
395
396
397                 if(ofs_new != 0.0f) {
398                         scalar_short= scalar_short_vgroup= ofs_new / 32767.0f;
399                         mv= mvert + ((ofs_new >= ofs_orig) ? 0 : numVerts);
400                         dv= dvert;
401                         for(i=0; i<numVerts; i++, mv++) {
402                                 if(dv) {
403                                         if(defgrp_invert)       scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
404                                         else                            scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
405                                         scalar_short_vgroup= (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
406                                         dv++;
407                                 }
408                                 VECADDFAC(mv->co, mv->co, mv->no, scalar_short_vgroup);
409                         }
410                 }
411
412                 if(ofs_orig != 0.0f) {
413                         scalar_short= scalar_short_vgroup= ofs_orig / 32767.0f;
414                         mv= mvert + ((ofs_new >= ofs_orig) ? numVerts : 0); /* same as above but swapped, intentional use of 'ofs_new' */
415                         dv= dvert;
416                         for(i=0; i<numVerts; i++, mv++) {
417                                 if(dv) {
418                                         if(defgrp_invert)       scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
419                                         else                            scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
420                                         scalar_short_vgroup= (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
421                                         dv++;
422                                 }
423                                 VECADDFAC(mv->co, mv->co, mv->no, scalar_short_vgroup);
424                         }
425                 }
426
427         }
428         else {
429                 /* make a face normal layer if not present */
430                 float (*face_nors)[3];
431                 int face_nors_calc= 0;
432
433                 /* same as EM_solidify() in editmesh_lib.c */
434                 float *vert_angles= MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
435                 float *vert_accum= vert_angles + numVerts;
436                 float *face_angles = NULL;
437                 BLI_array_staticdeclare(face_angles, 16); /* BM_NGON_STACK_SIZE */
438                 int j, vidx;
439
440                 face_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
441                 if(!face_nors) {
442                         face_nors = CustomData_add_layer(&dm->polyData, CD_NORMAL, CD_CALLOC, NULL, dm->numPolyData);
443                         face_nors_calc= 1;
444                 }
445
446                 if(vert_nors==NULL) {
447                         vert_nors= MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
448                         for(i=0, mv=mvert; i<numVerts; i++, mv++) {
449                                 normal_short_to_float_v3(vert_nors[i], mv->no);
450                         }
451                 }
452
453                 for (i=0, mp=mpoly; i<numFaces; i++, mp++) {
454                         mesh_calc_poly_normal(mp, mloop+mp->loopstart, mvert, face_nors[i]);
455                         
456                         /* just added, calc the normal */
457                         BLI_array_empty(face_angles);
458                         for (j=0, ml=mloop+mp->loopstart; j<mp->totloop; j++, ml++) {
459                                 MLoop *ml2 = mloop + mp->loopstart + (j+1)%mp->totloop; //next
460                                 MLoop *ml3 = mloop + mp->loopstart + (j+mp->totloop-1)%mp->totloop; //previous
461                                 float e1[3], e2[3], angle;
462                                 
463                                 sub_v3_v3v3(e1, mvert[ml2->v].co, mvert[ml->v].co);
464                                 sub_v3_v3v3(e2, mvert[ml3->v].co, mvert[ml->v].co);
465                                 angle = M_PI - angle_normalized_v3v3(e1, e2);
466                                 BLI_array_append(face_angles, angle);
467                         }
468                         
469                         for (j=0, ml=mloop+mp->loopstart; j<mp->totloop; j++, ml++) {
470                                 vidx = ml->v;
471                                 vert_accum[vidx] += face_angles[j];
472                                 vert_angles[vidx]+= shell_angle_to_dist(angle_normalized_v3v3(vert_nors[vidx], face_nors[i])) * face_angles[j];
473                         }
474                 }
475         
476                 BLI_array_free(face_angles);
477
478                 /* vertex group support */
479                 if(dvert) {
480                         float scalar;
481
482                         dv= dvert;
483                         if(defgrp_invert) {
484                                 for(i=0; i<numVerts; i++, dv++) {
485                                         scalar= 1.0f - defvert_find_weight(dv, defgrp_index);
486                                         scalar= offset_fac_vg + (scalar * offset_fac_vg_inv);
487                                         vert_angles[i] *= scalar;
488                                 }
489                         }
490                         else {
491                                 for(i=0; i<numVerts; i++, dv++) {
492                                         scalar= defvert_find_weight(dv, defgrp_index);
493                                         scalar= offset_fac_vg + (scalar * offset_fac_vg_inv);
494                                         vert_angles[i] *= scalar;
495                                 }
496                         }
497                 }
498
499                 if(ofs_new) {
500                         mv= mvert + ((ofs_new >= ofs_orig) ? 0 : numVerts);
501
502                         for(i=0; i<numVerts; i++, mv++) {
503                                 if(vert_accum[i]) { /* zero if unselected */
504                                         madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i]));
505                                 }
506                         }
507                 }
508
509                 if(ofs_orig) {
510                         mv= mvert + ((ofs_new >= ofs_orig) ? numVerts : 0); /* same as above but swapped, intentional use of 'ofs_new' */
511
512                         for(i=0; i<numVerts; i++, mv++) {
513                                 if(vert_accum[i]) { /* zero if unselected */
514                                         madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i]));
515                                 }
516                         }
517                 }
518
519                 MEM_freeN(vert_angles);
520         }
521
522         if(vert_nors)
523                 MEM_freeN(vert_nors);
524
525         /* flip vertex normals for copied verts */
526         mv= mvert + numVerts;
527         for(i=0; i<numVerts; i++, mv++) {
528                 mv->no[0]= -mv->no[0];
529                 mv->no[1]= -mv->no[1];
530                 mv->no[2]= -mv->no[2];
531         }
532
533         if(smd->flag & MOD_SOLIDIFY_RIM) {
534                 int *origindex;
535                 
536                 /* bugger, need to re-calculate the normals for the new edge faces.
537                  * This could be done in many ways, but probably the quickest way is to calculate the average normals for side faces only.
538                  * Then blend them with the normals of the edge verts.
539                  * 
540                  * at the moment its easiest to allocate an entire array for every vertex, even though we only need edge verts - campbell
541                  */
542                 
543 #define SOLIDIFY_SIDE_NORMALS
544
545 #ifdef SOLIDIFY_SIDE_NORMALS
546                 /* annoying to allocate these since we only need the edge verts, */
547                 float (*edge_vert_nos)[3]= MEM_callocN(sizeof(float) * numVerts * 3, "solidify_edge_nos");
548                 float nor[3];
549 #endif
550                 const unsigned char crease_rim= smd->crease_rim * 255.0f;
551                 const unsigned char crease_outer= smd->crease_outer * 255.0f;
552                 const unsigned char crease_inner= smd->crease_inner * 255.0f;
553
554                 /* add faces & edges */
555                 origindex= result->getEdgeDataArray(result, CD_ORIGINDEX);
556                 ed= medge + (numEdges * 2);
557                 for(i=0; i<newEdges; i++, ed++) {
558                         ed->v1= new_vert_arr[i];
559                         ed->v2= new_vert_arr[i] + numVerts;
560                         ed->flag |= ME_EDGEDRAW;
561
562                         origindex[numEdges * 2 + i]= ORIGINDEX_NONE;
563
564                         if(crease_rim)
565                                 ed->crease= crease_rim;
566                 }
567
568                 /* faces */
569                 edge_origIndex = origindex;
570                 origindex = DM_get_face_data_layer(result, CD_ORIGINDEX);
571                 
572                 mp = mpoly + (numFaces * 2);
573                 ml = mloop + (numLoops * 2);
574                 j = 0;
575                 for(i=0; i<newFaces; i++, mp++) {
576                         int eidx= new_edge_arr[i];
577                         int fidx= edge_users[eidx];
578                         int flip, k1, k2;
579                         MLoop *ml2;
580
581                         if(fidx >= numFaces) {
582                                 fidx -= numFaces;
583                                 flip= 1;
584                         }
585                         else {
586                                 flip= 0;
587                         }
588
589                         ed= medge + eidx;
590
591                         /* copy most of the face settings */
592                         DM_copy_face_data(dm, result, fidx, (numFaces * 2) + i, 1);
593                         mp->loopstart = j+numLoops*2;
594                         mp->flag = mpoly[fidx].flag;
595                         mp->totloop = 4;
596
597                         /* ME_HIDE for rim faces should match that of the rim edge, not the face the edge */
598                         mp->flag &= ~ME_HIDE;
599                         mp->flag |= ed->flag & ME_HIDE;
600                         
601                         ml2 = mloop + mpoly[fidx].loopstart;
602                         for (k1=0; k1<mpoly[fidx].totloop; k1++, ml2++) {
603                                 if (ml2->e == eidx)
604                                         break;
605                         }
606                         
607                         if (k1 == mpoly[fidx].totloop) {
608                                 fprintf(stderr, "%s: solidify bad k1==totloop (bmesh internal error)\n", __func__);
609                         }
610                         
611                         if (ed->v2 == mloop[mpoly[fidx].loopstart+k1].v) {
612                                 k2 = (k1 + mp->totloop - 1)%mp->totloop;
613                                 SWAP(int, k1, k2);
614                         }
615                         else if (ed->v1 == mloop[mpoly[fidx].loopstart+k1].v) {
616                                 k2 = (k1+1)%mp->totloop;
617                         }
618                         else {
619                                 fprintf(stderr, "%s: solidify bad edge/vert\n", __func__);
620                                 k2 = k1;
621                         }
622                         
623                         k1 += mpoly[fidx].loopstart;
624                         k2 += mpoly[fidx].loopstart;
625                         
626                         if(flip) {
627                                 CustomData_copy_data(&dm->loopData, &result->loopData, k1, numLoops*2+j, 1);
628                                 CustomData_copy_data(&dm->loopData, &result->loopData, k2, numLoops*2+j+1, 1);
629                                 CustomData_copy_data(&dm->loopData, &result->loopData, k2, numLoops*2+j+2, 1);
630                                 CustomData_copy_data(&dm->loopData, &result->loopData, k1, numLoops*2+j+3, 1);
631                                 
632                                 ml[j].v = ed->v1;
633                                 ml[j++].e = eidx;
634                                 
635                                 ml[j].v = ed->v2;
636                                 ml[j++].e = numEdges*2 + old_vert_arr[ed->v2];
637                                 
638                                 ml[j].v = ed->v2+numVerts;
639                                 ml[j++].e = eidx+numEdges;
640                                 
641                                 ml[j].v = ed->v1+numVerts;
642                                 ml[j++].e = numEdges*2 + old_vert_arr[ed->v1];
643                         }
644                         else {
645                                 CustomData_copy_data(&dm->loopData, &result->loopData, k1, numLoops*2+j, 1);
646                                 CustomData_copy_data(&dm->loopData, &result->loopData, k2, numLoops*2+j+1, 1);
647                                 CustomData_copy_data(&dm->loopData, &result->loopData, k2, numLoops*2+j+2, 1);
648                                 CustomData_copy_data(&dm->loopData, &result->loopData, k1, numLoops*2+j+3, 1);
649
650                                 ml[j].v = ed->v1+numVerts;
651                                 ml[j++].e = eidx+numEdges;
652
653                                 ml[j].v = ed->v2+numVerts;
654                                 ml[j++].e = numEdges*2 + old_vert_arr[ed->v2];
655                                 
656                                 ml[j].v = ed->v2;
657                                 ml[j++].e = eidx;
658                                 
659                                 ml[j].v = ed->v1;
660                                 ml[j++].e = numEdges*2 + old_vert_arr[ed->v1];
661                         }
662                         
663                         if (edge_origIndex) {
664                                 edge_origIndex[ml[j-3].e] = ORIGINDEX_NONE;
665                                 edge_origIndex[ml[j-1].e] = ORIGINDEX_NONE;
666                         }
667                         if(crease_outer) {
668                                 /* crease += crease_outer; without wrapping */
669                                 unsigned char *cr= (unsigned char *)&(ed->crease);
670                                 int tcr= *cr + crease_outer;
671                                 *cr= tcr > 255 ? 255 : tcr;
672                         }
673
674                         if(crease_inner) {
675                                 /* crease += crease_inner; without wrapping */
676                                 unsigned char *cr= (unsigned char *)&(medge[numEdges + eidx].crease);
677                                 int tcr= *cr + crease_inner;
678                                 *cr= tcr > 255 ? 255 : tcr;
679                         }
680                         
681 #ifdef SOLIDIFY_SIDE_NORMALS
682                         normal_quad_v3(nor, mvert[ml[j-4].v].co, mvert[ml[j-3].v].co, mvert[ml[j-2].v].co, mvert[ml[j-1].v].co);
683
684                         add_v3_v3(edge_vert_nos[ed->v1], nor);
685                         add_v3_v3(edge_vert_nos[ed->v2], nor);
686 #endif
687                 }
688                 
689 #ifdef SOLIDIFY_SIDE_NORMALS
690                 ed= medge + (numEdges * 2);
691                 for(i=0; i<newEdges; i++, ed++) {
692                         float nor_cpy[3];
693                         short *nor_short;
694                         int j;
695                         
696                         /* note, only the first vertex (lower half of the index) is calculated */
697                         normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]);
698                         
699                         for(j=0; j<2; j++) { /* loop over both verts of the edge */
700                                 nor_short= mvert[*(&ed->v1 + j)].no;
701                                 normal_short_to_float_v3(nor, nor_short);
702                                 add_v3_v3(nor, nor_cpy);
703                                 normalize_v3(nor);
704                                 normal_float_to_short_v3(nor_short, nor);
705                         }
706                 }
707
708                 MEM_freeN(edge_vert_nos);
709 #endif
710
711                 BLI_array_free(new_vert_arr);
712                 BLI_array_free(new_edge_arr);
713                 MEM_freeN(edge_users);
714                 MEM_freeN(edge_order);
715         }
716
717         if (old_vert_arr)
718                 MEM_freeN(old_vert_arr);
719         
720         /* must recalculate normals with vgroups since they can displace unevenly [#26888] */
721         if(dvert) {
722                 CDDM_calc_normals(result);
723         }
724         else {
725                 CDDM_recalc_tesselation(result);
726         }
727         
728         if (dm != odm) {
729                 dm->needsFree = 1;
730                 dm->release(dm);
731         }
732         
733         return result;
734 }
735
736 #undef SOLIDIFY_SIDE_NORMALS
737
738 static DerivedMesh *applyModifierEM(ModifierData *md,
739                                                          Object *ob,
740                                                          struct BMEditMesh *UNUSED(editData),
741                                                          DerivedMesh *derivedData)
742 {
743         return applyModifier(md, ob, derivedData, 0, 1);
744 }
745
746
747 ModifierTypeInfo modifierType_Solidify = {
748         /* name */              "Solidify",
749         /* structName */        "SolidifyModifierData",
750         /* structSize */        sizeof(SolidifyModifierData),
751         /* type */              eModifierTypeType_Constructive,
752
753         /* flags */             eModifierTypeFlag_AcceptsMesh
754                                                         | eModifierTypeFlag_AcceptsCVs
755                                                         | eModifierTypeFlag_SupportsMapping
756                                                         | eModifierTypeFlag_SupportsEditmode
757                                                         | eModifierTypeFlag_EnableInEditmode,
758
759         /* copyData */          copyData,
760         /* deformVerts */       NULL,
761         /* deformMatrices */    NULL,
762         /* deformVertsEM */     NULL,
763         /* deformMatricesEM */  NULL,
764         /* applyModifier */     applyModifier,
765         /* applyModifierEM */   applyModifierEM,
766         /* initData */          initData,
767         /* requiredDataMask */  requiredDataMask,
768         /* freeData */          NULL,
769         /* isDisabled */        NULL,
770         /* updateDepgraph */    NULL,
771         /* dependsOnTime */     NULL,
772         /* dependsOnNormals */  NULL,
773         /* foreachObjectLink */ NULL,
774         /* foreachIDLink */     NULL,
775         /* foreachTexLink */    NULL,
776 };