merge with/from trunk at r35190
[blender.git] / source / blender / modifiers / intern / MOD_solidify.c
1 /*
2 * $Id$
3 *
4 * ***** BEGIN GPL LICENSE BLOCK *****
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software  Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
21 * All rights reserved.
22 *
23 * Contributor(s): Daniel Dunbar
24 *                 Ton Roosendaal,
25 *                 Ben Batt,
26 *                 Brecht Van Lommel,
27 *                 Campbell Barton
28 *
29 * ***** END GPL LICENSE BLOCK *****
30 *
31 */
32
33 /** \file blender/modifiers/intern/MOD_solidify.c
34  *  \ingroup modifiers
35  */
36
37
38 #include "DNA_meshdata_types.h"
39
40 #include "BLI_math.h"
41 #include "BLI_edgehash.h"
42 #include "BLI_utildefines.h"
43
44 #include "BKE_cdderivedmesh.h"
45 #include "BKE_mesh.h"
46 #include "BKE_particle.h"
47 #include "BKE_deform.h"
48
49
50 #include "MOD_modifiertypes.h"
51
52 #include "MEM_guardedalloc.h"
53
54 typedef struct EdgeFaceRef {
55         int f1; /* init as -1 */
56         int f2;
57 } EdgeFaceRef;
58
59 static void dm_calc_normal(DerivedMesh *dm, float (*temp_nors)[3])
60 {
61         int i, numVerts, numEdges, numFaces;
62         MFace *mface, *mf;
63         MVert *mvert, *mv;
64
65         float (*face_nors)[3];
66         float *f_no;
67         int calc_face_nors= 0;
68
69         numVerts = dm->getNumVerts(dm);
70         numEdges = dm->getNumEdges(dm);
71         numFaces = dm->getNumFaces(dm);
72         mface = dm->getTessFaceArray(dm);
73         mvert = dm->getVertArray(dm);
74
75         /* we don't want to overwrite any referenced layers */
76
77         /*
78         Dosnt work here!
79         mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
80         cddm->mvert = mv;
81         */
82
83         face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
84         if(!face_nors) {
85                 calc_face_nors = 1;
86                 face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, numFaces);
87         }
88
89         mv = mvert;
90         mf = mface;
91
92         {
93                 EdgeHash *edge_hash = BLI_edgehash_new();
94                 EdgeHashIterator *edge_iter;
95                 int edge_ref_count = 0;
96                 int ed_v1, ed_v2; /* use when getting the key */
97                 EdgeFaceRef *edge_ref_array = MEM_callocN(numEdges * sizeof(EdgeFaceRef), "Edge Connectivity");
98                 EdgeFaceRef *edge_ref;
99                 float edge_normal[3];
100
101                 /* This function adds an edge hash if its not there, and adds the face index */
102 #define NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(EDV1, EDV2); \
103                                 edge_ref = (EdgeFaceRef *)BLI_edgehash_lookup(edge_hash, EDV1, EDV2); \
104                                 if (!edge_ref) { \
105                                         edge_ref = &edge_ref_array[edge_ref_count]; edge_ref_count++; \
106                                         edge_ref->f1=i; \
107                                         edge_ref->f2=-1; \
108                                         BLI_edgehash_insert(edge_hash, EDV1, EDV2, edge_ref); \
109                                 } else { \
110                                         edge_ref->f2=i; \
111                                 }
112
113                 for(i = 0; i < numFaces; i++, mf++) {
114                         f_no = face_nors[i];
115
116                         if(mf->v4) {
117                                 if(calc_face_nors)
118                                         normal_quad_v3(f_no, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
119
120                                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v1, mf->v2);
121                                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v2, mf->v3);
122                                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v3, mf->v4);
123                                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v4, mf->v1);
124                         } else {
125                                 if(calc_face_nors)
126                                         normal_tri_v3(f_no, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
127
128                                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v1, mf->v2);
129                                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v2, mf->v3);
130                                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v3, mf->v1);
131                         }
132                 }
133
134                 for(edge_iter = BLI_edgehashIterator_new(edge_hash); !BLI_edgehashIterator_isDone(edge_iter); BLI_edgehashIterator_step(edge_iter)) {
135                         /* Get the edge vert indices, and edge value (the face indices that use it)*/
136                         BLI_edgehashIterator_getKey(edge_iter, (int*)&ed_v1, (int*)&ed_v2);
137                         edge_ref = BLI_edgehashIterator_getValue(edge_iter);
138
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                                 add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
143                                 normalize_v3(edge_normal);
144                                 mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
145                         } else {
146                                 /* only one face attached to that edge */
147                                 /* an edge without another attached- the weight on this is
148                                  * undefined, M_PI/2 is 90d in radians and that seems good enough */
149                                 mul_v3_v3fl(edge_normal, face_nors[edge_ref->f1], M_PI/2);
150                         }
151                         add_v3_v3(temp_nors[ed_v1], edge_normal);
152                         add_v3_v3(temp_nors[ed_v2], edge_normal);
153                 }
154                 BLI_edgehashIterator_free(edge_iter);
155                 BLI_edgehash_free(edge_hash, NULL);
156                 MEM_freeN(edge_ref_array);
157         }
158
159         /* normalize vertex normals and assign */
160         for(i = 0; i < numVerts; i++, mv++) {
161                 if(normalize_v3(temp_nors[i]) == 0.0f) {
162                         normal_short_to_float_v3(temp_nors[i], mv->no);
163                 }
164         }
165 }
166  
167 static void initData(ModifierData *md)
168 {
169         SolidifyModifierData *smd = (SolidifyModifierData*) md;
170         smd->offset = 0.01f;
171         smd->offset_fac = -1.0f;
172         smd->flag = MOD_SOLIDIFY_RIM;
173 }
174  
175 static void copyData(ModifierData *md, ModifierData *target)
176 {
177         SolidifyModifierData *smd = (SolidifyModifierData*) md;
178         SolidifyModifierData *tsmd = (SolidifyModifierData*) target;
179         tsmd->offset = smd->offset;
180         tsmd->offset_fac = smd->offset_fac;
181         tsmd->crease_inner = smd->crease_inner;
182         tsmd->crease_outer = smd->crease_outer;
183         tsmd->crease_rim = smd->crease_rim;
184         tsmd->flag = smd->flag;
185         strcpy(tsmd->defgrp_name, smd->defgrp_name);
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
200 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, 
201                                                 DerivedMesh *dm,
202                                                 int UNUSED(useRenderParams),
203                                                 int UNUSED(isFinalCalc))
204 {
205         int i;
206         DerivedMesh *result, *copy;
207         const SolidifyModifierData *smd = (SolidifyModifierData*) md;
208
209         MFace *mf, *mface, *orig_mface;
210         MEdge *ed, *medge, *orig_medge;
211         MVert *mv, *mvert, *orig_mvert;
212
213         const int numVerts = dm->getNumVerts(dm);
214         const int numEdges = dm->getNumEdges(dm);
215         const int numFaces = dm->getNumFaces(dm);
216
217         /* use for edges */
218         int *new_vert_arr= NULL;
219         int newFaces = 0;
220
221         int *new_edge_arr= NULL;
222         int newEdges = 0;
223
224         int *edge_users= NULL;
225         char *edge_order= NULL;
226
227         float (*vert_nors)[3]= NULL;
228
229         float const ofs_orig=                           - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
230         float const ofs_new= smd->offset        - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
231
232         /* weights */
233         MDeformVert *dvert= NULL, *dv= NULL;
234         const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
235         const int defgrp_index= defgroup_name_index(ob, smd->defgrp_name);
236
237         if (defgrp_index >= 0)
238                 dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
239
240         orig_mface = dm->getTessFaceArray(dm);
241         orig_medge = dm->getEdgeArray(dm);
242         orig_mvert = dm->getVertArray(dm);
243
244         if(smd->flag & MOD_SOLIDIFY_RIM) {
245                 EdgeHash *edgehash = BLI_edgehash_new();
246                 EdgeHashIterator *ehi;
247                 int v1, v2;
248                 int eidx;
249
250                 for(i=0, mv=orig_mvert; i<numVerts; i++, mv++) {
251                         mv->flag &= ~ME_VERT_TMP_TAG;
252                 }
253
254                 for(i=0, ed=orig_medge; i<numEdges; i++, ed++) {
255                         BLI_edgehash_insert(edgehash, ed->v1, ed->v2, SET_INT_IN_POINTER(i));
256                 }
257
258 #define INVALID_UNUSED -1
259 #define INVALID_PAIR -2
260
261 #define ADD_EDGE_USER(_v1, _v2, edge_ord) \
262                 eidx= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edgehash, _v1, _v2)); \
263                 if(edge_users[eidx] == INVALID_UNUSED) { \
264                         ed= orig_medge + eidx; \
265                         edge_users[eidx]= (_v1 < _v2) == (ed->v1 < ed->v2) ? i:(i+numFaces); \
266                         edge_order[eidx]= edge_ord; \
267                 } else { \
268                         edge_users[eidx]= INVALID_PAIR; \
269                 } \
270
271
272                 edge_users= MEM_mallocN(sizeof(int) * numEdges, "solid_mod edges");
273                 edge_order= MEM_mallocN(sizeof(char) * numEdges, "solid_mod eorder");
274                 memset(edge_users, INVALID_UNUSED, sizeof(int) * numEdges);
275
276                 for(i=0, mf=orig_mface; i<numFaces; i++, mf++) {
277                         if(mf->v4) {
278                                 ADD_EDGE_USER(mf->v1, mf->v2, 0);
279                                 ADD_EDGE_USER(mf->v2, mf->v3, 1);
280                                 ADD_EDGE_USER(mf->v3, mf->v4, 2);
281                                 ADD_EDGE_USER(mf->v4, mf->v1, 3);
282                         }
283                         else {
284                                 ADD_EDGE_USER(mf->v1, mf->v2, 0);
285                                 ADD_EDGE_USER(mf->v2, mf->v3, 1);
286                                 ADD_EDGE_USER(mf->v3, mf->v1, 2);
287                         }
288                 }
289
290 #undef ADD_EDGE_USER
291 #undef INVALID_UNUSED
292 #undef INVALID_PAIR
293
294
295                 new_edge_arr= MEM_callocN(sizeof(int) * numEdges, "solid_mod arr");
296
297                 ehi= BLI_edgehashIterator_new(edgehash);
298                 for(; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
299                         eidx= GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
300                         if(edge_users[eidx] >= 0) {
301                                 BLI_edgehashIterator_getKey(ehi, &v1, &v2);
302                                 orig_mvert[v1].flag |= ME_VERT_TMP_TAG;
303                                 orig_mvert[v2].flag |= ME_VERT_TMP_TAG;
304                                 new_edge_arr[newFaces]= eidx;
305                                 newFaces++;
306                         }
307                 }
308                 BLI_edgehashIterator_free(ehi);
309
310
311
312                 new_vert_arr= MEM_callocN(sizeof(int) * numVerts, "solid_mod new_varr");
313                 for(i=0, mv=orig_mvert; i<numVerts; i++, mv++) {
314                         if(mv->flag & ME_VERT_TMP_TAG) {
315                                 new_vert_arr[newEdges] = i;
316                                 newEdges++;
317
318                                 mv->flag &= ~ME_VERT_TMP_TAG;
319                         }
320                 }
321
322                 BLI_edgehash_free(edgehash, NULL);
323         }
324
325         if(smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
326                 vert_nors= MEM_callocN(sizeof(float) * numVerts * 3, "mod_solid_vno_hq");
327                 dm_calc_normal(dm, vert_nors);
328         }
329
330         result = CDDM_from_template(dm, numVerts * 2, (numEdges * 2) + newEdges, (numFaces * 2) + newFaces, 0, 0);
331
332         mface = result->getTessFaceArray(result);
333         medge = result->getEdgeArray(result);
334         mvert = result->getVertArray(result);
335
336         DM_copy_face_data(dm, result, 0, 0, numFaces);
337         DM_copy_face_data(dm, result, 0, numFaces, numFaces);
338
339         DM_copy_edge_data(dm, result, 0, 0, numEdges);
340         DM_copy_edge_data(dm, result, 0, numEdges, numEdges);
341
342         DM_copy_vert_data(dm, result, 0, 0, numVerts);
343         DM_copy_vert_data(dm, result, 0, numVerts, numVerts);
344
345         {
346                 static int corner_indices[4] = {2, 1, 0, 3};
347                 int is_quad;
348
349                 for(i=0, mf=mface+numFaces; i<numFaces; i++, mf++) {
350                         mf->v1 += numVerts;
351                         mf->v2 += numVerts;
352                         mf->v3 += numVerts;
353                         if(mf->v4)
354                                 mf->v4 += numVerts;
355
356                         /* Flip face normal */
357                         {
358                                 is_quad = mf->v4;
359                                 SWAP(int, mf->v1, mf->v3);
360                                 DM_swap_tessface_data(result, i+numFaces, corner_indices);
361                                 test_index_face(mf, &result->faceData, numFaces, is_quad ? 4:3);
362                         }
363                 }
364         }
365
366         for(i=0, ed=medge+numEdges; i<numEdges; i++, ed++) {
367                 ed->v1 += numVerts;
368                 ed->v2 += numVerts;
369         }
370
371         /* note, copied vertex layers dont have flipped normals yet. do this after applying offset */
372         if((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
373                 /* no even thickness, very simple */
374                 float scalar_short;
375                 float scalar_short_vgroup;
376
377
378                 if(ofs_new != 0.0f) {
379                         scalar_short= scalar_short_vgroup= ofs_new / 32767.0f;
380                         mv= mvert + ((ofs_new >= ofs_orig) ? 0 : numVerts);
381                         dv= dvert;
382                         for(i=0; i<numVerts; i++, mv++) {
383                                 if(dv) {
384                                         if(defgrp_invert)       scalar_short_vgroup = scalar_short * (1.0f - defvert_find_weight(dv, defgrp_index));
385                                         else                            scalar_short_vgroup = scalar_short * defvert_find_weight(dv, defgrp_index);
386                                         dv++;
387                                 }
388                                 VECADDFAC(mv->co, mv->co, mv->no, scalar_short_vgroup);
389                         }
390                 }
391
392                 if(ofs_orig != 0.0f) {
393                         scalar_short= scalar_short_vgroup= ofs_orig / 32767.0f;
394                         mv= mvert + ((ofs_new >= ofs_orig) ? numVerts : 0); /* same as above but swapped, intentional use of 'ofs_new' */
395                         dv= dvert;
396                         for(i=0; i<numVerts; i++, mv++) {
397                                 if(dv) {
398                                         if(defgrp_invert)       scalar_short_vgroup = scalar_short * (1.0f - defvert_find_weight(dv, defgrp_index));
399                                         else                            scalar_short_vgroup = scalar_short * defvert_find_weight(dv, defgrp_index);
400                                         dv++;
401                                 }
402                                 VECADDFAC(mv->co, mv->co, mv->no, scalar_short_vgroup);
403                         }
404                 }
405
406         }
407         else {
408                 /* make a face normal layer if not present */
409                 float (*face_nors)[3];
410                 int face_nors_calc= 0;
411
412                 /* same as EM_solidify() in editmesh_lib.c */
413                 float *vert_angles= MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
414                 float *vert_accum= vert_angles + numVerts;
415                 float face_angles[4];
416                 int j, vidx;
417
418                 face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
419                 if(!face_nors) {
420                         face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, dm->numFaceData);
421                         face_nors_calc= 1;
422                 }
423
424                 if(vert_nors==NULL) {
425                         vert_nors= MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
426                         for(i=0, mv=mvert; i<numVerts; i++, mv++) {
427                                 normal_short_to_float_v3(vert_nors[i], mv->no);
428                         }
429                 }
430
431                 for(i=0, mf=mface; i<numFaces; i++, mf++) {
432
433                         /* just added, calc the normal */
434                         if(face_nors_calc) {
435                                 if(mf->v4)
436                                         normal_quad_v3(face_nors[i], mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
437                                 else
438                                         normal_tri_v3(face_nors[i] , mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co);
439                         }
440
441                         if(mf->v4) {
442                                 angle_quad_v3(face_angles, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
443                                 j= 3;
444                         }
445                         else {
446                                 angle_tri_v3(face_angles, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co);
447                                 j= 2;
448                         }
449
450                         do {
451                                 vidx = *(&mf->v1 + j);
452                                 vert_accum[vidx] += face_angles[j];
453                                 vert_angles[vidx]+= shell_angle_to_dist(angle_normalized_v3v3(vert_nors[vidx], face_nors[i])) * face_angles[j];
454                         } while(j--);
455                 }
456
457                 /* vertex group support */
458                 if(dvert) {
459                         dv= dvert;
460                         if(defgrp_invert) {
461                                 for(i=0; i<numVerts; i++, dv++) {
462                                         vert_angles[i] *= (1.0f - defvert_find_weight(dv, defgrp_index));
463                                 }
464                         }
465                         else {
466                                 for(i=0; i<numVerts; i++, dv++) {
467                                         vert_angles[i] *= defvert_find_weight(dv, defgrp_index);
468                                 }
469                         }
470                 }
471
472                 if(ofs_new) {
473                         mv= mvert + ((ofs_new >= ofs_orig) ? 0 : numVerts);
474
475                         for(i=0; i<numVerts; i++, mv++) {
476                                 if(vert_accum[i]) { /* zero if unselected */
477                                         madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i]));
478                                 }
479                         }
480                 }
481
482                 if(ofs_orig) {
483                         mv= mvert + ((ofs_new >= ofs_orig) ? numVerts : 0); /* same as above but swapped, intentional use of 'ofs_new' */
484
485                         for(i=0; i<numVerts; i++, mv++) {
486                                 if(vert_accum[i]) { /* zero if unselected */
487                                         madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i]));
488                                 }
489                         }
490                 }
491
492                 MEM_freeN(vert_angles);
493         }
494
495         if(vert_nors)
496                 MEM_freeN(vert_nors);
497
498         /* flip vertex normals for copied verts */
499         mv= mvert + numVerts;
500         for(i=0; i<numVerts; i++, mv++) {
501                 mv->no[0]= -mv->no[0];
502                 mv->no[1]= -mv->no[1];
503                 mv->no[2]= -mv->no[2];
504         }
505
506         if(smd->flag & MOD_SOLIDIFY_RIM) {
507
508                 
509                 /* bugger, need to re-calculate the normals for the new edge faces.
510                  * This could be done in many ways, but probably the quickest way is to calculate the average normals for side faces only.
511                  * Then blend them with the normals of the edge verts.
512                  * 
513                  * at the moment its easiest to allocate an entire array for every vertex, even though we only need edge verts - campbell
514                  */
515                 
516 #define SOLIDIFY_SIDE_NORMALS
517
518 #ifdef SOLIDIFY_SIDE_NORMALS
519                 /* annoying to allocate these since we only need the edge verts, */
520                 float (*edge_vert_nos)[3]= MEM_callocN(sizeof(float) * numVerts * 3, "solidify_edge_nos");
521                 float nor[3];
522 #endif
523                 /* maximum value -1, so we have room to increase */
524                 const short mat_nr_shift= (smd->flag & MOD_SOLIDIFY_RIM_MATERIAL) ? ob->totcol-1 : -1;
525
526                 const unsigned char crease_rim= smd->crease_rim * 255.0f;
527                 const unsigned char crease_outer= smd->crease_outer * 255.0f;
528                 const unsigned char crease_inner= smd->crease_inner * 255.0f;
529
530                 const int edge_indices[4][4] = {
531                                 {1, 0, 0, 1},
532                                 {2, 1, 1, 2},
533                                 {3, 2, 2, 3},
534                                 {0, 3, 3, 0}};
535
536                 /* add faces & edges */
537                 ed= medge + (numEdges * 2);
538                 for(i=0; i<newEdges; i++, ed++) {
539                         ed->v1= new_vert_arr[i];
540                         ed->v2= new_vert_arr[i] + numVerts;
541                         ed->flag |= ME_EDGEDRAW;
542
543                         if(crease_rim)
544                                 ed->crease= crease_rim;
545                 }
546
547                 /* faces */
548                 mf= mface + (numFaces * 2);
549                 for(i=0; i<newFaces; i++, mf++) {
550                         int eidx= new_edge_arr[i];
551                         int fidx= edge_users[eidx];
552                         int flip;
553
554                         if(fidx >= numFaces) {
555                                 fidx -= numFaces;
556                                 flip= 1;
557                         }
558                         else {
559                                 flip= 0;
560                         }
561
562                         ed= medge + eidx;
563
564                         /* copy most of the face settings */
565                         DM_copy_face_data(dm, result, fidx, (numFaces * 2) + i, 1);
566
567                         if(flip) {
568                                 DM_swap_tessface_data(result, (numFaces * 2) + i, edge_indices[edge_order[eidx]]);
569
570                                 mf->v1= ed->v1;
571                                 mf->v2= ed->v2;
572                                 mf->v3= ed->v2 + numVerts;
573                                 mf->v4= ed->v1 + numVerts;
574                         }
575                         else {
576                                 DM_swap_tessface_data(result, (numFaces * 2) + i, edge_indices[edge_order[eidx]]);
577
578                                 mf->v1= ed->v2;
579                                 mf->v2= ed->v1;
580                                 mf->v3= ed->v1 + numVerts;
581                                 mf->v4= ed->v2 + numVerts;
582                         }
583                         
584                         /* use the next material index if option enabled */
585                         if(mf->mat_nr < mat_nr_shift)
586                                 mf->mat_nr++;
587
588                         if(crease_outer)
589                                 ed->crease= crease_outer;
590
591                         if(crease_inner) {
592                                 medge[numEdges + eidx].crease= crease_inner;
593                         }
594                         
595 #ifdef SOLIDIFY_SIDE_NORMALS
596                         normal_quad_v3(nor, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
597
598                         add_v3_v3(edge_vert_nos[ed->v1], nor);
599                         add_v3_v3(edge_vert_nos[ed->v2], nor);
600 #endif
601                 }
602                 
603 #ifdef SOLIDIFY_SIDE_NORMALS
604                 ed= medge + (numEdges * 2);
605                 for(i=0; i<newEdges; i++, ed++) {
606                         float nor_cpy[3];
607                         short *nor_short;
608                         int j;
609                         
610                         /* note, only the first vertex (lower half of the index) is calculated */
611                         normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]);
612                         
613                         for(j=0; j<2; j++) { /* loop over both verts of the edge */
614                                 nor_short= mvert[*(&ed->v1 + j)].no;
615                                 normal_short_to_float_v3(nor, nor_short);
616                                 add_v3_v3(nor, nor_cpy);
617                                 normalize_v3(nor);
618                                 normal_float_to_short_v3(nor_short, nor);
619                         }
620                 }
621
622                 MEM_freeN(edge_vert_nos);
623 #endif
624
625                 MEM_freeN(new_vert_arr);
626                 MEM_freeN(new_edge_arr);
627                 MEM_freeN(edge_users);
628                 MEM_freeN(edge_order);
629         }
630
631         copy = CDDM_copy(result, 1); /*builds ngon faces from tess (mface) faces*/
632         result->needsFree = 1;
633         result->release(result);
634
635         return copy;
636 }
637
638 #undef SOLIDIFY_SIDE_NORMALS
639
640 static DerivedMesh *applyModifierEM(ModifierData *md,
641                                                          Object *ob,
642                                                          struct EditMesh *UNUSED(editData),
643                                                          DerivedMesh *derivedData)
644 {
645         return applyModifier(md, ob, derivedData, 0, 1);
646 }
647
648
649 ModifierTypeInfo modifierType_Solidify = {
650         /* name */              "Solidify",
651         /* structName */        "SolidifyModifierData",
652         /* structSize */        sizeof(SolidifyModifierData),
653         /* type */              eModifierTypeType_Constructive,
654
655         /* flags */             eModifierTypeFlag_AcceptsMesh
656                                                         | eModifierTypeFlag_AcceptsCVs
657                                                         | eModifierTypeFlag_SupportsMapping
658                                                         | eModifierTypeFlag_SupportsEditmode
659                                                         | eModifierTypeFlag_EnableInEditmode,
660
661         /* copyData */          copyData,
662         /* deformVerts */       NULL,
663         /* deformMatrices */    NULL,
664         /* deformVertsEM */     NULL,
665         /* deformMatricesEM */  NULL,
666         /* applyModifier */     applyModifier,
667         /* applyModifierEM */   applyModifierEM,
668         /* initData */          initData,
669         /* requiredDataMask */  requiredDataMask,
670         /* freeData */          NULL,
671         /* isDisabled */        NULL,
672         /* updateDepgraph */    NULL,
673         /* dependsOnTime */     NULL,
674         /* dependsOnNormals */  NULL,
675         /* foreachObjectLink */ NULL,
676         /* foreachIDLink */     NULL
677 };