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