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