Blender V2.61 - r43446

MOD_solidify.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software  Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Daniel Dunbar
00022  *                 Ton Roosendaal,
00023  *                 Ben Batt,
00024  *                 Brecht Van Lommel,
00025  *                 Campbell Barton
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  *
00029  */
00030 
00036 #include "DNA_meshdata_types.h"
00037 
00038 #include "BLI_math.h"
00039 #include "BLI_edgehash.h"
00040 #include "BLI_utildefines.h"
00041 #include "BLI_string.h"
00042 
00043 #include "MEM_guardedalloc.h"
00044 
00045 #include "BKE_cdderivedmesh.h"
00046 #include "BKE_mesh.h"
00047 #include "BKE_particle.h"
00048 #include "BKE_deform.h"
00049 
00050 #include "MOD_modifiertypes.h"
00051 #include "MOD_util.h"
00052 
00053 
00054 typedef struct EdgeFaceRef {
00055     int f1; /* init as -1 */
00056     int f2;
00057 } EdgeFaceRef;
00058 
00059 static void dm_calc_normal(DerivedMesh *dm, float (*temp_nors)[3])
00060 {
00061     int i, numVerts, numEdges, numFaces;
00062     MFace *mface, *mf;
00063     MVert *mvert, *mv;
00064 
00065     float (*face_nors)[3];
00066     float *f_no;
00067     int calc_face_nors= 0;
00068 
00069     numVerts = dm->getNumVerts(dm);
00070     numEdges = dm->getNumEdges(dm);
00071     numFaces = dm->getNumFaces(dm);
00072     mface = dm->getFaceArray(dm);
00073     mvert = dm->getVertArray(dm);
00074 
00075     /* we don't want to overwrite any referenced layers */
00076 
00077     /*
00078     Doesn't work here!
00079     mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts);
00080     cddm->mvert = mv;
00081     */
00082 
00083     face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
00084     if(!face_nors) {
00085         calc_face_nors = 1;
00086         face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, numFaces);
00087     }
00088 
00089     mv = mvert;
00090     mf = mface;
00091 
00092     {
00093         EdgeHash *edge_hash = BLI_edgehash_new();
00094         EdgeHashIterator *edge_iter;
00095         int edge_ref_count = 0;
00096         unsigned int ed_v1, ed_v2; /* use when getting the key */
00097         EdgeFaceRef *edge_ref_array = MEM_callocN(numEdges * sizeof(EdgeFaceRef), "Edge Connectivity");
00098         EdgeFaceRef *edge_ref;
00099         float edge_normal[3];
00100 
00101         /* This function adds an edge hash if its not there, and adds the face index */
00102 #define NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(EDV1, EDV2); \
00103             { \
00104                 const unsigned int ml_v1 = EDV1; \
00105                 const unsigned int ml_v2 = EDV2; \
00106                 edge_ref = (EdgeFaceRef *)BLI_edgehash_lookup(edge_hash, ml_v1, ml_v2); \
00107                 if (!edge_ref) { \
00108                     edge_ref = &edge_ref_array[edge_ref_count]; edge_ref_count++; \
00109                     edge_ref->f1 = i; \
00110                     edge_ref->f2 =- 1; \
00111                     BLI_edgehash_insert(edge_hash, ml_v1, ml_v2, edge_ref); \
00112                 } \
00113                 else { \
00114                     edge_ref->f2 = i; \
00115                 } \
00116             }
00117         /* --- end define --- */
00118 
00119         for(i = 0; i < numFaces; i++, mf++) {
00120             f_no = face_nors[i];
00121 
00122             if(mf->v4) {
00123                 if(calc_face_nors)
00124                     normal_quad_v3(f_no, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
00125 
00126                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v1, mf->v2);
00127                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v2, mf->v3);
00128                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v3, mf->v4);
00129                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v4, mf->v1);
00130             } else {
00131                 if(calc_face_nors)
00132                     normal_tri_v3(f_no, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
00133 
00134                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v1, mf->v2);
00135                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v2, mf->v3);
00136                 NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v3, mf->v1);
00137             }
00138         }
00139 
00140         for(edge_iter = BLI_edgehashIterator_new(edge_hash); !BLI_edgehashIterator_isDone(edge_iter); BLI_edgehashIterator_step(edge_iter)) {
00141             /* Get the edge vert indices, and edge value (the face indices that use it)*/
00142             BLI_edgehashIterator_getKey(edge_iter, &ed_v1, &ed_v2);
00143             edge_ref = BLI_edgehashIterator_getValue(edge_iter);
00144 
00145             if (edge_ref->f2 != -1) {
00146                 /* We have 2 faces using this edge, calculate the edges normal
00147                  * using the angle between the 2 faces as a weighting */
00148                 add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
00149                 normalize_v3(edge_normal);
00150                 mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
00151             } else {
00152                 /* only one face attached to that edge */
00153                 /* an edge without another attached- the weight on this is
00154                  * undefined, M_PI/2 is 90d in radians and that seems good enough */
00155                 mul_v3_v3fl(edge_normal, face_nors[edge_ref->f1], M_PI/2);
00156             }
00157             add_v3_v3(temp_nors[ed_v1], edge_normal);
00158             add_v3_v3(temp_nors[ed_v2], edge_normal);
00159         }
00160         BLI_edgehashIterator_free(edge_iter);
00161         BLI_edgehash_free(edge_hash, NULL);
00162         MEM_freeN(edge_ref_array);
00163     }
00164 
00165     /* normalize vertex normals and assign */
00166     for(i = 0; i < numVerts; i++, mv++) {
00167         if(normalize_v3(temp_nors[i]) == 0.0f) {
00168             normal_short_to_float_v3(temp_nors[i], mv->no);
00169         }
00170     }
00171 }
00172  
00173 static void initData(ModifierData *md)
00174 {
00175     SolidifyModifierData *smd = (SolidifyModifierData*) md;
00176     smd->offset = 0.01f;
00177     smd->offset_fac = -1.0f;
00178     smd->flag = MOD_SOLIDIFY_RIM;
00179 }
00180  
00181 static void copyData(ModifierData *md, ModifierData *target)
00182 {
00183     SolidifyModifierData *smd = (SolidifyModifierData*) md;
00184     SolidifyModifierData *tsmd = (SolidifyModifierData*) target;
00185     tsmd->offset = smd->offset;
00186     tsmd->offset_fac = smd->offset_fac;
00187     tsmd->crease_inner = smd->crease_inner;
00188     tsmd->crease_outer = smd->crease_outer;
00189     tsmd->crease_rim = smd->crease_rim;
00190     tsmd->flag = smd->flag;
00191     BLI_strncpy(tsmd->defgrp_name, smd->defgrp_name, sizeof(tsmd->defgrp_name));
00192 }
00193 
00194 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
00195 {
00196     SolidifyModifierData *smd = (SolidifyModifierData*) md;
00197     CustomDataMask dataMask = 0;
00198 
00199     /* ask for vertexgroups if we need them */
00200     if(smd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
00201 
00202     return dataMask;
00203 }
00204 
00205 
00206 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, 
00207                         DerivedMesh *dm,
00208                         int UNUSED(useRenderParams),
00209                         int UNUSED(isFinalCalc))
00210 {
00211     int i;
00212     DerivedMesh *result;
00213     const SolidifyModifierData *smd = (SolidifyModifierData*) md;
00214 
00215     MFace *mf, *mface, *orig_mface;
00216     MEdge *ed, *medge, *orig_medge;
00217     MVert *mv, *mvert, *orig_mvert;
00218 
00219     const int numVerts = dm->getNumVerts(dm);
00220     const int numEdges = dm->getNumEdges(dm);
00221     const int numFaces = dm->getNumFaces(dm);
00222 
00223     /* only use material offsets if we have 2 or more materials  */
00224     const short mat_nr_max= ob->totcol > 1 ? ob->totcol - 1 : 0;
00225     const short mat_ofs= mat_nr_max ? smd->mat_ofs : 0;
00226     const short mat_ofs_rim= mat_nr_max ? smd->mat_ofs_rim : 0;
00227 
00228     /* use for edges */
00229     int *new_vert_arr= NULL;
00230     int newFaces = 0;
00231 
00232     int *new_edge_arr= NULL;
00233     int newEdges = 0;
00234 
00235     int *edge_users= NULL;
00236     char *edge_order= NULL;
00237 
00238     float (*vert_nors)[3]= NULL;
00239 
00240     const float ofs_orig=               - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
00241     const float ofs_new= smd->offset    - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
00242     const float offset_fac_vg= smd->offset_fac_vg;
00243     const float offset_fac_vg_inv= 1.0f - smd->offset_fac_vg;
00244 
00245     /* weights */
00246     MDeformVert *dvert, *dv= NULL;
00247     const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
00248     int defgrp_index;
00249 
00250     modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
00251 
00252     orig_mface = dm->getFaceArray(dm);
00253     orig_medge = dm->getEdgeArray(dm);
00254     orig_mvert = dm->getVertArray(dm);
00255 
00256     if(smd->flag & MOD_SOLIDIFY_RIM) {
00257         EdgeHash *edgehash = BLI_edgehash_new();
00258         EdgeHashIterator *ehi;
00259         unsigned int v1, v2;
00260         int eidx;
00261 
00262         for(i=0, mv=orig_mvert; i<numVerts; i++, mv++) {
00263             mv->flag &= ~ME_VERT_TMP_TAG;
00264         }
00265 
00266         for(i=0, ed=orig_medge; i<numEdges; i++, ed++) {
00267             BLI_edgehash_insert(edgehash, ed->v1, ed->v2, SET_INT_IN_POINTER(i));
00268         }
00269 
00270 #define INVALID_UNUSED -1
00271 #define INVALID_PAIR -2
00272 
00273 #define ADD_EDGE_USER(_v1, _v2, edge_ord) \
00274         { \
00275             const unsigned int ml_v1 = _v1; \
00276             const unsigned int ml_v2 = _v2; \
00277             eidx= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edgehash, ml_v1, ml_v2)); \
00278             if(edge_users[eidx] == INVALID_UNUSED) { \
00279                 ed= orig_medge + eidx; \
00280                 edge_users[eidx] = (ml_v1 < ml_v2) == (ed->v1 < ed->v2) ? i : (i + numFaces); \
00281                 edge_order[eidx] = edge_ord; \
00282             } \
00283             else { \
00284                 edge_users[eidx] = INVALID_PAIR; \
00285             } \
00286         }
00287 
00288 
00289         edge_users= MEM_mallocN(sizeof(int) * numEdges, "solid_mod edges");
00290         edge_order= MEM_mallocN(sizeof(char) * numEdges, "solid_mod eorder");
00291         memset(edge_users, INVALID_UNUSED, sizeof(int) * numEdges);
00292 
00293         for(i=0, mf=orig_mface; i<numFaces; i++, mf++) {
00294             if(mf->v4) {
00295                 ADD_EDGE_USER(mf->v1, mf->v2, 0);
00296                 ADD_EDGE_USER(mf->v2, mf->v3, 1);
00297                 ADD_EDGE_USER(mf->v3, mf->v4, 2);
00298                 ADD_EDGE_USER(mf->v4, mf->v1, 3);
00299             }
00300             else {
00301                 ADD_EDGE_USER(mf->v1, mf->v2, 0);
00302                 ADD_EDGE_USER(mf->v2, mf->v3, 1);
00303                 ADD_EDGE_USER(mf->v3, mf->v1, 2);
00304             }
00305         }
00306 
00307 #undef ADD_EDGE_USER
00308 #undef INVALID_UNUSED
00309 #undef INVALID_PAIR
00310 
00311 
00312         new_edge_arr= MEM_callocN(sizeof(int) * numEdges, "solid_mod arr");
00313 
00314         ehi= BLI_edgehashIterator_new(edgehash);
00315         for(; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
00316             eidx= GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
00317             if(edge_users[eidx] >= 0) {
00318                 BLI_edgehashIterator_getKey(ehi, &v1, &v2);
00319                 orig_mvert[v1].flag |= ME_VERT_TMP_TAG;
00320                 orig_mvert[v2].flag |= ME_VERT_TMP_TAG;
00321                 new_edge_arr[newFaces]= eidx;
00322                 newFaces++;
00323             }
00324         }
00325         BLI_edgehashIterator_free(ehi);
00326 
00327 
00328 
00329         new_vert_arr= MEM_callocN(sizeof(int) * numVerts, "solid_mod new_varr");
00330         for(i=0, mv=orig_mvert; i<numVerts; i++, mv++) {
00331             if(mv->flag & ME_VERT_TMP_TAG) {
00332                 new_vert_arr[newEdges] = i;
00333                 newEdges++;
00334 
00335                 mv->flag &= ~ME_VERT_TMP_TAG;
00336             }
00337         }
00338 
00339         BLI_edgehash_free(edgehash, NULL);
00340     }
00341 
00342     if(smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
00343         vert_nors= MEM_callocN(sizeof(float) * numVerts * 3, "mod_solid_vno_hq");
00344         dm_calc_normal(dm, vert_nors);
00345     }
00346 
00347     result = CDDM_from_template(dm, numVerts * 2, (numEdges * 2) + newEdges, (numFaces * 2) + newFaces);    
00348 
00349     mface = result->getFaceArray(result);
00350     medge = result->getEdgeArray(result);
00351     mvert = result->getVertArray(result);
00352 
00353     DM_copy_face_data(dm, result, 0, 0, numFaces);
00354     DM_copy_face_data(dm, result, 0, numFaces, numFaces);
00355 
00356     DM_copy_edge_data(dm, result, 0, 0, numEdges);
00357     DM_copy_edge_data(dm, result, 0, numEdges, numEdges);
00358 
00359     DM_copy_vert_data(dm, result, 0, 0, numVerts);
00360     DM_copy_vert_data(dm, result, 0, numVerts, numVerts);
00361 
00362     {
00363         static int corner_indices[4] = {2, 1, 0, 3};
00364         unsigned int is_quad;
00365 
00366         for(i=0, mf=mface+numFaces; i<numFaces; i++, mf++) {
00367             mf->v1 += numVerts;
00368             mf->v2 += numVerts;
00369             mf->v3 += numVerts;
00370             if(mf->v4)
00371                 mf->v4 += numVerts;
00372 
00373             /* Flip face normal */
00374             {
00375                 is_quad = mf->v4;
00376                 SWAP(unsigned int, mf->v1, mf->v3);
00377                 DM_swap_face_data(result, i+numFaces, corner_indices);
00378                 test_index_face(mf, &result->faceData, numFaces, is_quad ? 4:3);
00379             }
00380 
00381             if(mat_ofs) {
00382                 mf->mat_nr += mat_ofs;
00383                 CLAMP(mf->mat_nr, 0, mat_nr_max);
00384             }
00385         }
00386     }
00387 
00388     for(i=0, ed=medge+numEdges; i<numEdges; i++, ed++) {
00389         ed->v1 += numVerts;
00390         ed->v2 += numVerts;
00391     }
00392 
00393     /* note, copied vertex layers dont have flipped normals yet. do this after applying offset */
00394     if((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
00395         /* no even thickness, very simple */
00396         float scalar_short;
00397         float scalar_short_vgroup;
00398 
00399 
00400         if(ofs_new != 0.0f) {
00401             scalar_short= scalar_short_vgroup= ofs_new / 32767.0f;
00402             mv= mvert + ((ofs_new >= ofs_orig) ? 0 : numVerts);
00403             dv= dvert;
00404             for(i=0; i<numVerts; i++, mv++) {
00405                 if(dv) {
00406                     if(defgrp_invert)   scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
00407                     else                scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
00408                     scalar_short_vgroup= (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
00409                     dv++;
00410                 }
00411                 VECADDFAC(mv->co, mv->co, mv->no, scalar_short_vgroup);
00412             }
00413         }
00414 
00415         if(ofs_orig != 0.0f) {
00416             scalar_short= scalar_short_vgroup= ofs_orig / 32767.0f;
00417             mv= mvert + ((ofs_new >= ofs_orig) ? numVerts : 0); /* same as above but swapped, intentional use of 'ofs_new' */
00418             dv= dvert;
00419             for(i=0; i<numVerts; i++, mv++) {
00420                 if(dv) {
00421                     if(defgrp_invert)   scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
00422                     else                scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
00423                     scalar_short_vgroup= (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
00424                     dv++;
00425                 }
00426                 VECADDFAC(mv->co, mv->co, mv->no, scalar_short_vgroup);
00427             }
00428         }
00429 
00430     }
00431     else {
00432         /* make a face normal layer if not present */
00433         float (*face_nors)[3];
00434         int face_nors_calc= 0;
00435 
00436         /* same as EM_solidify() in editmesh_lib.c */
00437         float *vert_angles= MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
00438         float *vert_accum= vert_angles + numVerts;
00439         float face_angles[4];
00440         int j, vidx;
00441 
00442         face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
00443         if(!face_nors) {
00444             face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, dm->numFaceData);
00445             face_nors_calc= 1;
00446         }
00447 
00448         if(vert_nors==NULL) {
00449             vert_nors= MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
00450             for(i=0, mv=mvert; i<numVerts; i++, mv++) {
00451                 normal_short_to_float_v3(vert_nors[i], mv->no);
00452             }
00453         }
00454 
00455         for(i=0, mf=mface; i<numFaces; i++, mf++) {
00456 
00457             /* just added, calc the normal */
00458             if(face_nors_calc) {
00459                 if(mf->v4)
00460                     normal_quad_v3(face_nors[i], mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
00461                 else
00462                     normal_tri_v3(face_nors[i] , mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co);
00463             }
00464 
00465             if(mf->v4) {
00466                 angle_quad_v3(face_angles, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
00467                 j= 3;
00468             }
00469             else {
00470                 angle_tri_v3(face_angles, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co);
00471                 j= 2;
00472             }
00473 
00474             do {
00475                 vidx = *(&mf->v1 + j);
00476                 vert_accum[vidx] += face_angles[j];
00477                 vert_angles[vidx]+= shell_angle_to_dist(angle_normalized_v3v3(vert_nors[vidx], face_nors[i])) * face_angles[j];
00478             } while(j--);
00479         }
00480 
00481         /* vertex group support */
00482         if(dvert) {
00483             float scalar;
00484 
00485             dv= dvert;
00486             if(defgrp_invert) {
00487                 for(i=0; i<numVerts; i++, dv++) {
00488                     scalar= 1.0f - defvert_find_weight(dv, defgrp_index);
00489                     scalar= offset_fac_vg + (scalar * offset_fac_vg_inv);
00490                     vert_angles[i] *= scalar;
00491                 }
00492             }
00493             else {
00494                 for(i=0; i<numVerts; i++, dv++) {
00495                     scalar= defvert_find_weight(dv, defgrp_index);
00496                     scalar= offset_fac_vg + (scalar * offset_fac_vg_inv);
00497                     vert_angles[i] *= scalar;
00498                 }
00499             }
00500         }
00501 
00502         if(ofs_new) {
00503             mv= mvert + ((ofs_new >= ofs_orig) ? 0 : numVerts);
00504 
00505             for(i=0; i<numVerts; i++, mv++) {
00506                 if(vert_accum[i]) { /* zero if unselected */
00507                     madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i]));
00508                 }
00509             }
00510         }
00511 
00512         if(ofs_orig) {
00513             mv= mvert + ((ofs_new >= ofs_orig) ? numVerts : 0); /* same as above but swapped, intentional use of 'ofs_new' */
00514 
00515             for(i=0; i<numVerts; i++, mv++) {
00516                 if(vert_accum[i]) { /* zero if unselected */
00517                     madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i]));
00518                 }
00519             }
00520         }
00521 
00522         MEM_freeN(vert_angles);
00523     }
00524 
00525     if(vert_nors)
00526         MEM_freeN(vert_nors);
00527 
00528     /* flip vertex normals for copied verts */
00529     mv= mvert + numVerts;
00530     for(i=0; i<numVerts; i++, mv++) {
00531         mv->no[0]= -mv->no[0];
00532         mv->no[1]= -mv->no[1];
00533         mv->no[2]= -mv->no[2];
00534     }
00535 
00536     if(smd->flag & MOD_SOLIDIFY_RIM) {
00537         int *origindex;
00538         
00539         /* bugger, need to re-calculate the normals for the new edge faces.
00540          * This could be done in many ways, but probably the quickest way is to calculate the average normals for side faces only.
00541          * Then blend them with the normals of the edge verts.
00542          * 
00543          * at the moment its easiest to allocate an entire array for every vertex, even though we only need edge verts - campbell
00544          */
00545         
00546 #define SOLIDIFY_SIDE_NORMALS
00547 
00548 #ifdef SOLIDIFY_SIDE_NORMALS
00549         /* annoying to allocate these since we only need the edge verts, */
00550         float (*edge_vert_nos)[3]= MEM_callocN(sizeof(float) * numVerts * 3, "solidify_edge_nos");
00551         float nor[3];
00552 #endif
00553         const unsigned char crease_rim= smd->crease_rim * 255.0f;
00554         const unsigned char crease_outer= smd->crease_outer * 255.0f;
00555         const unsigned char crease_inner= smd->crease_inner * 255.0f;
00556 
00557         const int edge_indices[2][4][4] = {
00558                 /* quad */
00559                {{1, 0, 0, 1},
00560                 {2, 1, 1, 2},
00561                 {3, 2, 2, 3},
00562                 {0, 3, 3, 0}},
00563                 /* tri */
00564                {{1, 0, 0, 1},
00565                 {2, 1, 1, 2},
00566                 {0, 2, 2, 0},
00567                 {0, 0, 0, 0}} /* unused for tris */
00568                 };
00569 
00570         /* add faces & edges */
00571         origindex= result->getEdgeDataArray(result, CD_ORIGINDEX);
00572         ed= medge + (numEdges * 2);
00573         for(i=0; i<newEdges; i++, ed++) {
00574             ed->v1= new_vert_arr[i];
00575             ed->v2= new_vert_arr[i] + numVerts;
00576             ed->flag |= ME_EDGEDRAW;
00577 
00578             origindex[numEdges * 2 + i]= ORIGINDEX_NONE;
00579 
00580             if(crease_rim)
00581                 ed->crease= crease_rim;
00582         }
00583 
00584         /* faces */
00585         mf= mface + (numFaces * 2);
00586         origindex= result->getFaceDataArray(result, CD_ORIGINDEX);
00587         for(i=0; i<newFaces; i++, mf++) {
00588             int eidx= new_edge_arr[i];
00589             int fidx= edge_users[eidx];
00590             int flip;
00591             int is_tri;
00592 
00593             if(fidx >= numFaces) {
00594                 fidx -= numFaces;
00595                 flip= 1;
00596             }
00597             else {
00598                 flip= 0;
00599             }
00600 
00601             ed= medge + eidx;
00602 
00603             /* copy most of the face settings */
00604             DM_copy_face_data(dm, result, fidx, (numFaces * 2) + i, 1);
00605 
00606             is_tri = (orig_mface[fidx].v4 == 0);
00607 
00608             if(flip) {
00609                 DM_swap_face_data(result, (numFaces * 2) + i, edge_indices[is_tri][edge_order[eidx]]);
00610 
00611                 mf->v1= ed->v1;
00612                 mf->v2= ed->v2;
00613                 mf->v3= ed->v2 + numVerts;
00614                 mf->v4= ed->v1 + numVerts;
00615             }
00616             else {
00617                 DM_swap_face_data(result, (numFaces * 2) + i, edge_indices[is_tri][edge_order[eidx]]);
00618 
00619                 mf->v1= ed->v2;
00620                 mf->v2= ed->v1;
00621                 mf->v3= ed->v1 + numVerts;
00622                 mf->v4= ed->v2 + numVerts;
00623             }
00624             
00625             /* use the next material index if option enabled */
00626             if(mat_ofs_rim) {
00627                 mf->mat_nr += mat_ofs_rim;
00628                 CLAMP(mf->mat_nr, 0, mat_nr_max);
00629             }
00630             if(crease_outer) {
00631                 /* crease += crease_outer; without wrapping */
00632                 unsigned char *cr= (unsigned char *)&(ed->crease);
00633                 int tcr= *cr + crease_outer;
00634                 *cr= tcr > 255 ? 255 : tcr;
00635             }
00636 
00637             if(crease_inner) {
00638                 /* crease += crease_inner; without wrapping */
00639                 unsigned char *cr= (unsigned char *)&(medge[numEdges + eidx].crease);
00640                 int tcr= *cr + crease_inner;
00641                 *cr= tcr > 255 ? 255 : tcr;
00642             }
00643             
00644 #ifdef SOLIDIFY_SIDE_NORMALS
00645             normal_quad_v3(nor, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
00646 
00647             add_v3_v3(edge_vert_nos[ed->v1], nor);
00648             add_v3_v3(edge_vert_nos[ed->v2], nor);
00649 #endif
00650         }
00651         
00652 #ifdef SOLIDIFY_SIDE_NORMALS
00653         ed= medge + (numEdges * 2);
00654         for(i=0; i<newEdges; i++, ed++) {
00655             float nor_cpy[3];
00656             short *nor_short;
00657             int j;
00658             
00659             /* note, only the first vertex (lower half of the index) is calculated */
00660             normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]);
00661             
00662             for(j=0; j<2; j++) { /* loop over both verts of the edge */
00663                 nor_short= mvert[*(&ed->v1 + j)].no;
00664                 normal_short_to_float_v3(nor, nor_short);
00665                 add_v3_v3(nor, nor_cpy);
00666                 normalize_v3(nor);
00667                 normal_float_to_short_v3(nor_short, nor);
00668             }
00669         }
00670 
00671         MEM_freeN(edge_vert_nos);
00672 #endif
00673 
00674         MEM_freeN(new_vert_arr);
00675         MEM_freeN(new_edge_arr);
00676         MEM_freeN(edge_users);
00677         MEM_freeN(edge_order);
00678     }
00679 
00680     /* must recalculate normals with vgroups since they can displace unevenly [#26888] */
00681     if(dvert) {
00682         CDDM_calc_normals(result);
00683     }
00684 
00685     return result;
00686 }
00687 
00688 #undef SOLIDIFY_SIDE_NORMALS
00689 
00690 static DerivedMesh *applyModifierEM(ModifierData *md,
00691                              Object *ob,
00692                              struct EditMesh *UNUSED(editData),
00693                              DerivedMesh *derivedData)
00694 {
00695     return applyModifier(md, ob, derivedData, 0, 1);
00696 }
00697 
00698 
00699 ModifierTypeInfo modifierType_Solidify = {
00700     /* name */              "Solidify",
00701     /* structName */        "SolidifyModifierData",
00702     /* structSize */        sizeof(SolidifyModifierData),
00703     /* type */              eModifierTypeType_Constructive,
00704 
00705     /* flags */             eModifierTypeFlag_AcceptsMesh
00706                             | eModifierTypeFlag_AcceptsCVs
00707                             | eModifierTypeFlag_SupportsMapping
00708                             | eModifierTypeFlag_SupportsEditmode
00709                             | eModifierTypeFlag_EnableInEditmode,
00710 
00711     /* copyData */          copyData,
00712     /* deformVerts */       NULL,
00713     /* deformMatrices */    NULL,
00714     /* deformVertsEM */     NULL,
00715     /* deformMatricesEM */  NULL,
00716     /* applyModifier */     applyModifier,
00717     /* applyModifierEM */   applyModifierEM,
00718     /* initData */          initData,
00719     /* requiredDataMask */  requiredDataMask,
00720     /* freeData */          NULL,
00721     /* isDisabled */        NULL,
00722     /* updateDepgraph */    NULL,
00723     /* dependsOnTime */     NULL,
00724     /* dependsOnNormals */  NULL,
00725     /* foreachObjectLink */ NULL,
00726     /* foreachIDLink */     NULL,
00727     /* foreachTexLink */    NULL,
00728 };