Reverting r41409 (broken fix for #29089)
[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_math.h"
39 #include "BLI_edgehash.h"
40 #include "BLI_utildefines.h"
41 #include "BLI_string.h"
42
43 #include "BKE_cdderivedmesh.h"
44 #include "BKE_mesh.h"
45 #include "BKE_particle.h"
46 #include "BKE_deform.h"
47
48
49 #include "MOD_modifiertypes.h"
50 #include "MOD_util.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->getFaceArray(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         BLI_strncpy(tsmd->defgrp_name, smd->defgrp_name, sizeof(tsmd->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;
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         /* only use material offsets if we have 2 or more materials  */
218         const short mat_nr_max= ob->totcol > 1 ? ob->totcol - 1 : 0;
219         const short mat_ofs= mat_nr_max ? smd->mat_ofs : 0;
220         const short mat_ofs_rim= mat_nr_max ? smd->mat_ofs_rim : 0;
221
222         /* use for edges */
223         int *new_vert_arr= NULL;
224         int newFaces = 0;
225
226         int *new_edge_arr= NULL;
227         int newEdges = 0;
228
229         int *edge_users= NULL;
230         char *edge_order= NULL;
231
232         float (*vert_nors)[3]= NULL;
233
234         const float ofs_orig=                           - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
235         const float ofs_new= smd->offset        - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
236         const float offset_fac_vg= smd->offset_fac_vg;
237         const float offset_fac_vg_inv= 1.0f - smd->offset_fac_vg;
238
239         /* weights */
240         MDeformVert *dvert, *dv= NULL;
241         const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
242         int defgrp_index;
243
244         modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
245
246         orig_mface = dm->getFaceArray(dm);
247         orig_medge = dm->getEdgeArray(dm);
248         orig_mvert = dm->getVertArray(dm);
249
250         if(smd->flag & MOD_SOLIDIFY_RIM) {
251                 EdgeHash *edgehash = BLI_edgehash_new();
252                 EdgeHashIterator *ehi;
253                 int v1, v2;
254                 int eidx;
255
256                 for(i=0, mv=orig_mvert; i<numVerts; i++, mv++) {
257                         mv->flag &= ~ME_VERT_TMP_TAG;
258                 }
259
260                 for(i=0, ed=orig_medge; i<numEdges; i++, ed++) {
261                         BLI_edgehash_insert(edgehash, ed->v1, ed->v2, SET_INT_IN_POINTER(i));
262                 }
263
264 #define INVALID_UNUSED -1
265 #define INVALID_PAIR -2
266
267 #define ADD_EDGE_USER(_v1, _v2, edge_ord) \
268                 eidx= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edgehash, _v1, _v2)); \
269                 if(edge_users[eidx] == INVALID_UNUSED) { \
270                         ed= orig_medge + eidx; \
271                         edge_users[eidx]= (_v1 < _v2) == (ed->v1 < ed->v2) ? i:(i+numFaces); \
272                         edge_order[eidx]= edge_ord; \
273                 } else { \
274                         edge_users[eidx]= INVALID_PAIR; \
275                 } \
276
277
278                 edge_users= MEM_mallocN(sizeof(int) * numEdges, "solid_mod edges");
279                 edge_order= MEM_mallocN(sizeof(char) * numEdges, "solid_mod eorder");
280                 memset(edge_users, INVALID_UNUSED, sizeof(int) * numEdges);
281
282                 for(i=0, mf=orig_mface; i<numFaces; i++, mf++) {
283                         if(mf->v4) {
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->v4, 2);
287                                 ADD_EDGE_USER(mf->v4, mf->v1, 3);
288                         }
289                         else {
290                                 ADD_EDGE_USER(mf->v1, mf->v2, 0);
291                                 ADD_EDGE_USER(mf->v2, mf->v3, 1);
292                                 ADD_EDGE_USER(mf->v3, mf->v1, 2);
293                         }
294                 }
295
296 #undef ADD_EDGE_USER
297 #undef INVALID_UNUSED
298 #undef INVALID_PAIR
299
300
301                 new_edge_arr= MEM_callocN(sizeof(int) * numEdges, "solid_mod arr");
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                                 new_edge_arr[newFaces]= eidx;
311                                 newFaces++;
312                         }
313                 }
314                 BLI_edgehashIterator_free(ehi);
315
316
317
318                 new_vert_arr= MEM_callocN(sizeof(int) * numVerts, "solid_mod new_varr");
319                 for(i=0, mv=orig_mvert; i<numVerts; i++, mv++) {
320                         if(mv->flag & ME_VERT_TMP_TAG) {
321                                 new_vert_arr[newEdges] = i;
322                                 newEdges++;
323
324                                 mv->flag &= ~ME_VERT_TMP_TAG;
325                         }
326                 }
327
328                 BLI_edgehash_free(edgehash, NULL);
329         }
330
331         if(smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
332                 vert_nors= MEM_callocN(sizeof(float) * numVerts * 3, "mod_solid_vno_hq");
333                 dm_calc_normal(dm, vert_nors);
334         }
335
336         result = CDDM_from_template(dm, numVerts * 2, (numEdges * 2) + newEdges, (numFaces * 2) + newFaces);    
337
338         mface = result->getFaceArray(result);
339         medge = result->getEdgeArray(result);
340         mvert = result->getVertArray(result);
341
342         DM_copy_face_data(dm, result, 0, 0, numFaces);
343         DM_copy_face_data(dm, result, 0, numFaces, numFaces);
344
345         DM_copy_edge_data(dm, result, 0, 0, numEdges);
346         DM_copy_edge_data(dm, result, 0, numEdges, numEdges);
347
348         DM_copy_vert_data(dm, result, 0, 0, numVerts);
349         DM_copy_vert_data(dm, result, 0, numVerts, numVerts);
350
351         {
352                 static int corner_indices[4] = {2, 1, 0, 3};
353                 int is_quad;
354
355                 for(i=0, mf=mface+numFaces; i<numFaces; i++, mf++) {
356                         mf->v1 += numVerts;
357                         mf->v2 += numVerts;
358                         mf->v3 += numVerts;
359                         if(mf->v4)
360                                 mf->v4 += numVerts;
361
362                         /* Flip face normal */
363                         {
364                                 is_quad = mf->v4;
365                                 SWAP(int, mf->v1, mf->v3);
366                                 DM_swap_face_data(result, i+numFaces, corner_indices);
367                                 test_index_face(mf, &result->faceData, numFaces, is_quad ? 4:3);
368                         }
369
370                         if(mat_ofs) {
371                                 mf->mat_nr += mat_ofs;
372                                 CLAMP(mf->mat_nr, 0, mat_nr_max);
373                         }
374                 }
375         }
376
377         for(i=0, ed=medge+numEdges; i<numEdges; i++, ed++) {
378                 ed->v1 += numVerts;
379                 ed->v2 += numVerts;
380         }
381
382         /* note, copied vertex layers dont have flipped normals yet. do this after applying offset */
383         if((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
384                 /* no even thickness, very simple */
385                 float scalar_short;
386                 float scalar_short_vgroup;
387
388
389                 if(ofs_new != 0.0f) {
390                         scalar_short= scalar_short_vgroup= ofs_new / 32767.0f;
391                         mv= mvert + ((ofs_new >= ofs_orig) ? 0 : numVerts);
392                         dv= dvert;
393                         for(i=0; i<numVerts; i++, mv++) {
394                                 if(dv) {
395                                         if(defgrp_invert)       scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
396                                         else                            scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
397                                         scalar_short_vgroup= (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
398                                         dv++;
399                                 }
400                                 VECADDFAC(mv->co, mv->co, mv->no, scalar_short_vgroup);
401                         }
402                 }
403
404                 if(ofs_orig != 0.0f) {
405                         scalar_short= scalar_short_vgroup= ofs_orig / 32767.0f;
406                         mv= mvert + ((ofs_new >= ofs_orig) ? numVerts : 0); /* same as above but swapped, intentional use of 'ofs_new' */
407                         dv= dvert;
408                         for(i=0; i<numVerts; i++, mv++) {
409                                 if(dv) {
410                                         if(defgrp_invert)       scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
411                                         else                            scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
412                                         scalar_short_vgroup= (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
413                                         dv++;
414                                 }
415                                 VECADDFAC(mv->co, mv->co, mv->no, scalar_short_vgroup);
416                         }
417                 }
418
419         }
420         else {
421                 /* make a face normal layer if not present */
422                 float (*face_nors)[3];
423                 int face_nors_calc= 0;
424
425                 /* same as EM_solidify() in editmesh_lib.c */
426                 float *vert_angles= MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
427                 float *vert_accum= vert_angles + numVerts;
428                 float face_angles[4];
429                 int j, vidx;
430
431                 face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
432                 if(!face_nors) {
433                         face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, dm->numFaceData);
434                         face_nors_calc= 1;
435                 }
436
437                 if(vert_nors==NULL) {
438                         vert_nors= MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
439                         for(i=0, mv=mvert; i<numVerts; i++, mv++) {
440                                 normal_short_to_float_v3(vert_nors[i], mv->no);
441                         }
442                 }
443
444                 for(i=0, mf=mface; i<numFaces; i++, mf++) {
445
446                         /* just added, calc the normal */
447                         if(face_nors_calc) {
448                                 if(mf->v4)
449                                         normal_quad_v3(face_nors[i], mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
450                                 else
451                                         normal_tri_v3(face_nors[i] , mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co);
452                         }
453
454                         if(mf->v4) {
455                                 angle_quad_v3(face_angles, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
456                                 j= 3;
457                         }
458                         else {
459                                 angle_tri_v3(face_angles, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co);
460                                 j= 2;
461                         }
462
463                         do {
464                                 vidx = *(&mf->v1 + j);
465                                 vert_accum[vidx] += face_angles[j];
466                                 vert_angles[vidx]+= shell_angle_to_dist(angle_normalized_v3v3(vert_nors[vidx], face_nors[i])) * face_angles[j];
467                         } while(j--);
468                 }
469
470                 /* vertex group support */
471                 if(dvert) {
472                         float scalar;
473
474                         dv= dvert;
475                         if(defgrp_invert) {
476                                 for(i=0; i<numVerts; i++, dv++) {
477                                         scalar= 1.0f - defvert_find_weight(dv, defgrp_index);
478                                         scalar= offset_fac_vg + (scalar * offset_fac_vg_inv);
479                                         vert_angles[i] *= scalar;
480                                 }
481                         }
482                         else {
483                                 for(i=0; i<numVerts; i++, dv++) {
484                                         scalar= defvert_find_weight(dv, defgrp_index);
485                                         scalar= offset_fac_vg + (scalar * offset_fac_vg_inv);
486                                         vert_angles[i] *= scalar;
487                                 }
488                         }
489                 }
490
491                 if(ofs_new) {
492                         mv= mvert + ((ofs_new >= ofs_orig) ? 0 : numVerts);
493
494                         for(i=0; i<numVerts; i++, mv++) {
495                                 if(vert_accum[i]) { /* zero if unselected */
496                                         madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i]));
497                                 }
498                         }
499                 }
500
501                 if(ofs_orig) {
502                         mv= mvert + ((ofs_new >= ofs_orig) ? numVerts : 0); /* same as above but swapped, intentional use of 'ofs_new' */
503
504                         for(i=0; i<numVerts; i++, mv++) {
505                                 if(vert_accum[i]) { /* zero if unselected */
506                                         madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i]));
507                                 }
508                         }
509                 }
510
511                 MEM_freeN(vert_angles);
512         }
513
514         if(vert_nors)
515                 MEM_freeN(vert_nors);
516
517         /* flip vertex normals for copied verts */
518         mv= mvert + numVerts;
519         for(i=0; i<numVerts; i++, mv++) {
520                 mv->no[0]= -mv->no[0];
521                 mv->no[1]= -mv->no[1];
522                 mv->no[2]= -mv->no[2];
523         }
524
525         if(smd->flag & MOD_SOLIDIFY_RIM) {
526                 int *origindex;
527                 
528                 /* bugger, need to re-calculate the normals for the new edge faces.
529                  * This could be done in many ways, but probably the quickest way is to calculate the average normals for side faces only.
530                  * Then blend them with the normals of the edge verts.
531                  * 
532                  * at the moment its easiest to allocate an entire array for every vertex, even though we only need edge verts - campbell
533                  */
534                 
535 #define SOLIDIFY_SIDE_NORMALS
536
537 #ifdef SOLIDIFY_SIDE_NORMALS
538                 /* annoying to allocate these since we only need the edge verts, */
539                 float (*edge_vert_nos)[3]= MEM_callocN(sizeof(float) * numVerts * 3, "solidify_edge_nos");
540                 float nor[3];
541 #endif
542                 const unsigned char crease_rim= smd->crease_rim * 255.0f;
543                 const unsigned char crease_outer= smd->crease_outer * 255.0f;
544                 const unsigned char crease_inner= smd->crease_inner * 255.0f;
545
546                 const int edge_indices[4][4] = {
547                                 {1, 0, 0, 1},
548                                 {2, 1, 1, 2},
549                                 {3, 2, 2, 3},
550                                 {0, 3, 3, 0}};
551
552                 /* add faces & edges */
553                 origindex= result->getEdgeDataArray(result, CD_ORIGINDEX);
554                 ed= medge + (numEdges * 2);
555                 for(i=0; i<newEdges; i++, ed++) {
556                         ed->v1= new_vert_arr[i];
557                         ed->v2= new_vert_arr[i] + numVerts;
558                         ed->flag |= ME_EDGEDRAW;
559
560                         origindex[numEdges * 2 + i]= ORIGINDEX_NONE;
561
562                         if(crease_rim)
563                                 ed->crease= crease_rim;
564                 }
565
566                 /* faces */
567                 mf= mface + (numFaces * 2);
568                 origindex= result->getFaceDataArray(result, CD_ORIGINDEX);
569                 for(i=0; i<newFaces; i++, mf++) {
570                         int eidx= new_edge_arr[i];
571                         int fidx= edge_users[eidx];
572                         int flip;
573
574                         if(fidx >= numFaces) {
575                                 fidx -= numFaces;
576                                 flip= 1;
577                         }
578                         else {
579                                 flip= 0;
580                         }
581
582                         ed= medge + eidx;
583
584                         /* copy most of the face settings */
585                         DM_copy_face_data(dm, result, fidx, (numFaces * 2) + i, 1);
586
587                         if(flip) {
588                                 DM_swap_face_data(result, (numFaces * 2) + i, edge_indices[edge_order[eidx]]);
589
590                                 mf->v1= ed->v1;
591                                 mf->v2= ed->v2;
592                                 mf->v3= ed->v2 + numVerts;
593                                 mf->v4= ed->v1 + numVerts;
594                         }
595                         else {
596                                 DM_swap_face_data(result, (numFaces * 2) + i, edge_indices[edge_order[eidx]]);
597
598                                 mf->v1= ed->v2;
599                                 mf->v2= ed->v1;
600                                 mf->v3= ed->v1 + numVerts;
601                                 mf->v4= ed->v2 + numVerts;
602                         }
603                         
604                         /* use the next material index if option enabled */
605                         if(mat_ofs_rim) {
606                                 mf->mat_nr += mat_ofs_rim;
607                                 CLAMP(mf->mat_nr, 0, mat_nr_max);
608                         }
609                         if(crease_outer) {
610                                 /* crease += crease_outer; without wrapping */
611                                 unsigned char *cr= (unsigned char *)&(ed->crease);
612                                 int tcr= *cr + crease_outer;
613                                 *cr= tcr > 255 ? 255 : tcr;
614                         }
615
616                         if(crease_inner) {
617                                 /* crease += crease_inner; without wrapping */
618                                 unsigned char *cr= (unsigned char *)&(medge[numEdges + eidx].crease);
619                                 int tcr= *cr + crease_inner;
620                                 *cr= tcr > 255 ? 255 : tcr;
621                         }
622                         
623 #ifdef SOLIDIFY_SIDE_NORMALS
624                         normal_quad_v3(nor, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
625
626                         add_v3_v3(edge_vert_nos[ed->v1], nor);
627                         add_v3_v3(edge_vert_nos[ed->v2], nor);
628 #endif
629                         origindex[numFaces * 2 + i]= ORIGINDEX_NONE;
630                 }
631                 
632 #ifdef SOLIDIFY_SIDE_NORMALS
633                 ed= medge + (numEdges * 2);
634                 for(i=0; i<newEdges; i++, ed++) {
635                         float nor_cpy[3];
636                         short *nor_short;
637                         int j;
638                         
639                         /* note, only the first vertex (lower half of the index) is calculated */
640                         normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]);
641                         
642                         for(j=0; j<2; j++) { /* loop over both verts of the edge */
643                                 nor_short= mvert[*(&ed->v1 + j)].no;
644                                 normal_short_to_float_v3(nor, nor_short);
645                                 add_v3_v3(nor, nor_cpy);
646                                 normalize_v3(nor);
647                                 normal_float_to_short_v3(nor_short, nor);
648                         }
649                 }
650
651                 MEM_freeN(edge_vert_nos);
652 #endif
653
654                 MEM_freeN(new_vert_arr);
655                 MEM_freeN(new_edge_arr);
656                 MEM_freeN(edge_users);
657                 MEM_freeN(edge_order);
658         }
659
660         /* must recalculate normals with vgroups since they can displace unevenly [#26888] */
661         if(dvert) {
662                 CDDM_calc_normals(result);
663         }
664
665         return result;
666 }
667
668 #undef SOLIDIFY_SIDE_NORMALS
669
670 static DerivedMesh *applyModifierEM(ModifierData *md,
671                                                          Object *ob,
672                                                          struct EditMesh *UNUSED(editData),
673                                                          DerivedMesh *derivedData)
674 {
675         return applyModifier(md, ob, derivedData, 0, 1);
676 }
677
678
679 ModifierTypeInfo modifierType_Solidify = {
680         /* name */              "Solidify",
681         /* structName */        "SolidifyModifierData",
682         /* structSize */        sizeof(SolidifyModifierData),
683         /* type */              eModifierTypeType_Constructive,
684
685         /* flags */             eModifierTypeFlag_AcceptsMesh
686                                                         | eModifierTypeFlag_AcceptsCVs
687                                                         | eModifierTypeFlag_SupportsMapping
688                                                         | eModifierTypeFlag_SupportsEditmode
689                                                         | eModifierTypeFlag_EnableInEditmode,
690
691         /* copyData */          copyData,
692         /* deformVerts */       NULL,
693         /* deformMatrices */    NULL,
694         /* deformVertsEM */     NULL,
695         /* deformMatricesEM */  NULL,
696         /* applyModifier */     applyModifier,
697         /* applyModifierEM */   applyModifierEM,
698         /* initData */          initData,
699         /* requiredDataMask */  requiredDataMask,
700         /* freeData */          NULL,
701         /* isDisabled */        NULL,
702         /* updateDepgraph */    NULL,
703         /* dependsOnTime */     NULL,
704         /* dependsOnNormals */  NULL,
705         /* foreachObjectLink */ NULL,
706         /* foreachIDLink */     NULL,
707         /* foreachTexLink */    NULL,
708 };