svn merge ^/trunk/blender -r42957:42967
[blender.git] / source / blender / modifiers / intern / MOD_mirror.c
index c130af158bb1dfde9d00081111bab1803cf4ca20..30d205c198f4e68bde774a329f05884f10122add 100644 (file)
 #include "DNA_object_types.h"
 
 #include "BLI_math.h"
-#include "BLI_utildefines.h"
+#include "BLI_array.h"
 
 #include "BKE_cdderivedmesh.h"
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BKE_deform.h"
-
+#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
 
 #include "MEM_guardedalloc.h"
 #include "depsgraph_private.h"
 
-#include "MOD_util.h"
-
 static void initData(ModifierData *md)
 {
        MirrorModifierData *mmd = (MirrorModifierData*) md;
@@ -99,190 +98,166 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
                                    DerivedMesh *dm,
                                    int axis)
 {
-       int i;
-       float tolerance = mmd->tolerance;
-       DerivedMesh *result;
-       int numVerts, numEdges, numFaces;
-       int maxVerts = dm->getNumVerts(dm);
-       int maxEdges = dm->getNumEdges(dm);
-       int maxFaces = dm->getNumFaces(dm);
-       int *flip_map= NULL, flip_map_len= 0;
-       int do_vgroup_mirr= (mmd->flag & MOD_MIR_VGROUP);
-       unsigned int (*indexMap)[2];
-       float mtx[4][4], imtx[4][4];
-
-       numVerts = numEdges = numFaces = 0;
-
-       indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap");
-
-       result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2);
-
-
-       if (do_vgroup_mirr) {
-               flip_map= defgroup_flip_map(ob, &flip_map_len, FALSE);
-               if(flip_map == NULL)
-                       do_vgroup_mirr= 0;
+       float tolerance_sq;
+       DerivedMesh *cddm, *origdm;
+       bDeformGroup *def;
+       bDeformGroup **vector_def = NULL;
+       MVert *mv, *ov;
+       MEdge *me;
+       MLoop *ml;
+       MPoly *mp;
+       float mtx[4][4];
+       int i, j, *vtargetmap = NULL;
+       BLI_array_declare(vtargetmap);
+       int vector_size=0, a, totshape;
+
+       tolerance_sq = mmd->tolerance * mmd->tolerance;
+       
+       origdm = dm;
+       if (!CDDM_Check(dm))
+               dm = CDDM_copy(dm, 0);
+       
+       if (mmd->flag & MOD_MIR_VGROUP) {
+               /* calculate the number of deformedGroups */
+               for(vector_size = 0, def = ob->defbase.first; def;
+                       def = def->next, vector_size++);
+
+               /* load the deformedGroups for fast access */
+               vector_def =
+                       (bDeformGroup **)MEM_mallocN(sizeof(bDeformGroup*) * vector_size,
+                                                                                "group_index");
+               for(a = 0, def = ob->defbase.first; def; def = def->next, a++) {
+                       vector_def[a] = def;
+               }
        }
 
+       /*mtx is the mirror transformation*/
+       unit_m4(mtx);
+       mtx[axis][axis] = -1.0;
+
        if (mmd->mirror_ob) {
-               float obinv[4][4];
-               
-               invert_m4_m4(obinv, mmd->mirror_ob->obmat);
-               mult_m4_m4m4(mtx, obinv, ob->obmat);
-               invert_m4_m4(imtx, mtx);
+               float tmp[4][4];
+               float itmp[4][4];
+
+               /*tmp is a transform from coords relative to the object's own origin, to
+                 coords relative to the mirror object origin*/
+               invert_m4_m4(tmp, mmd->mirror_ob->obmat);
+               mult_m4_m4m4(tmp, tmp, ob->obmat);
+
+               /*itmp is the reverse transform back to origin-relative coordiantes*/
+               invert_m4_m4(itmp, tmp);
+
+               /*combine matrices to get a single matrix that translates coordinates into
+                 mirror-object-relative space, does the mirror, and translates back to
+                 origin-relative space*/
+               mult_m4_m4m4(mtx, mtx, tmp);
+               mult_m4_m4m4(mtx, itmp, mtx);
        }
-
-       for(i = 0; i < maxVerts; i++) {
-               MVert inMV;
-               MVert *mv = CDDM_get_vert(result, numVerts);
-               int isShared;
-               float co[3];
-               
-               dm->getVert(dm, i, &inMV);
-               
-               copy_v3_v3(co, inMV.co);
-               
-               if (mmd->mirror_ob) {
-                       mul_m4_v3(mtx, co);
-               }
-               
-               if(mmd->flag & MOD_MIR_NO_MERGE)
-                       isShared = 0;
-               else
-                       isShared = ABS(co[axis])<=tolerance;
-               
-               /* Because the topology result (# of vertices) must be the same if
-                * the mesh data is overridden by vertex cos, have to calc sharedness
-                * based on original coordinates. This is why we test before copy.
-                */
-               DM_copy_vert_data(dm, result, i, numVerts, 1);
-               *mv = inMV;
-
-               indexMap[i][0] = numVerts;
-               indexMap[i][1] = !isShared;
-
-               numVerts++;
-
-               if(isShared ) {
-                       co[axis] = 0.0f;
-                       if (mmd->mirror_ob) {
-                               mul_m4_v3(imtx, co);
-                       }
-                       copy_v3_v3(mv->co, co);
-                       
-                       mv->flag |= ME_VERT_MERGED;
+       
+       cddm = CDDM_from_template(dm, dm->numVertData*2, dm->numEdgeData*2, 0, dm->numLoopData*2, dm->numPolyData*2);
+       
+       /*copy customdata to original geometry*/
+       CustomData_copy_data(&dm->vertData, &cddm->vertData, 0, 0, dm->numVertData);
+       CustomData_copy_data(&dm->edgeData, &cddm->edgeData, 0, 0, dm->numEdgeData);
+       CustomData_copy_data(&dm->loopData, &cddm->loopData, 0, 0, dm->numLoopData);
+       CustomData_copy_data(&dm->polyData, &cddm->polyData, 0, 0, dm->numPolyData);
+
+       /*copy customdata to new geometry*/
+       CustomData_copy_data(&dm->vertData, &cddm->vertData, 0, dm->numVertData, dm->numVertData);
+       CustomData_copy_data(&dm->edgeData, &cddm->edgeData, 0, dm->numEdgeData, dm->numEdgeData);
+       CustomData_copy_data(&dm->polyData, &cddm->polyData, 0, dm->numPolyData, dm->numPolyData);
+       
+       /*mirror vertex coordinates*/
+       ov = CDDM_get_verts(cddm);
+       mv = ov + dm->numVertData;
+       for (i=0; i<dm->numVertData; i++, mv++, ov++) {
+               mul_m4_v3(mtx, mv->co);
+               /*compare location of the original and mirrored vertex, to see if they
+                 should be mapped for merging*/
+               if (len_squared_v3v3(ov->co, mv->co) < tolerance_sq) {
+                       BLI_array_append(vtargetmap, i+dm->numVertData);
                }
                else {
-                       MVert *mv2 = CDDM_get_vert(result, numVerts);
-                       
-                       DM_copy_vert_data(dm, result, i, numVerts, 1);
-                       *mv2 = *mv;
-                       
-                       co[axis] = -co[axis];
-                       if (mmd->mirror_ob) {
-                               mul_m4_v3(imtx, co);
-                       }
-                       copy_v3_v3(mv2->co, co);
-                       
-                       if (do_vgroup_mirr) {
-                               MDeformVert *dvert= DM_get_vert_data(result, numVerts, CD_MDEFORMVERT);
-                               if(dvert) {
-                                       defvert_flip(dvert, flip_map, flip_map_len);
-                               }
-                       }
-
-                       numVerts++;
+                       BLI_array_append(vtargetmap, -1);
                }
        }
-
-       for(i = 0; i < maxEdges; i++) {
-               MEdge inMED;
-               MEdge *med = CDDM_get_edge(result, numEdges);
-               
-               dm->getEdge(dm, i, &inMED);
-               
-               DM_copy_edge_data(dm, result, i, numEdges, 1);
-               *med = inMED;
-               numEdges++;
-               
-               med->v1 = indexMap[inMED.v1][0];
-               med->v2 = indexMap[inMED.v2][0];
-               
-               if(indexMap[inMED.v1][1] || indexMap[inMED.v2][1]) {
-                       MEdge *med2 = CDDM_get_edge(result, numEdges);
-                       
-                       DM_copy_edge_data(dm, result, i, numEdges, 1);
-                       *med2 = *med;
-                       numEdges++;
-                       
-                       med2->v1 += indexMap[inMED.v1][1];
-                       med2->v2 += indexMap[inMED.v2][1];
+       
+       /*handle shape keys*/
+       totshape = CustomData_number_of_layers(&cddm->vertData, CD_SHAPEKEY);
+       for (a=0; a<totshape; a++) {
+               float (*cos)[3] = CustomData_get_layer_n(&cddm->vertData, CD_SHAPEKEY, a);
+               for (i=dm->numVertData; i<cddm->numVertData; i++) {
+                       mul_m4_v3(mtx, cos[i]);
                }
        }
-
-       for(i = 0; i < maxFaces; i++) {
-               MFace inMF;
-               MFace *mf = CDDM_get_face(result, numFaces);
-               
-               dm->getFace(dm, i, &inMF);
-               
-               DM_copy_face_data(dm, result, i, numFaces, 1);
-               *mf = inMF;
-               numFaces++;
+       
+       for (i=0; i<dm->numVertData; i++) {
+               BLI_array_append(vtargetmap, -1);
+       }
+       
+       /*adjust mirrored edge vertex indices*/
+       me = CDDM_get_edges(cddm) + dm->numEdgeData;
+       for (i=0; i<dm->numEdgeData; i++, me++) {
+               me->v1 += dm->numVertData;
+               me->v2 += dm->numVertData;
+       }
+       
+       /*adjust mirrored poly loopstart indices, and reverse loop order (normals)*/    
+       mp = CDDM_get_polys(cddm) + dm->numPolyData;
+       ml = CDDM_get_loops(cddm);
+       for (i=0; i<dm->numPolyData; i++, mp++) {
+               MLoop *ml2;
+               int e;
                
-               mf->v1 = indexMap[inMF.v1][0];
-               mf->v2 = indexMap[inMF.v2][0];
-               mf->v3 = indexMap[inMF.v3][0];
-               mf->v4 = indexMap[inMF.v4][0];
+               for (j=0; j<mp->totloop; j++) {
+                       CustomData_copy_data(&dm->loopData, &cddm->loopData, mp->loopstart+j,
+                                                                mp->loopstart+dm->numLoopData+mp->totloop-j-1, 1);
+               }
                
-               if ( indexMap[inMF.v1][1] ||
-                    indexMap[inMF.v2][1] ||
-                    indexMap[inMF.v3][1] ||
-                    (mf->v4 && indexMap[inMF.v4][1]))
-               {
-                       MFace *mf2 = CDDM_get_face(result, numFaces);
-                       static int corner_indices[4] = {2, 1, 0, 3};
-                       
-                       DM_copy_face_data(dm, result, i, numFaces, 1);
-                       *mf2 = *mf;
-                       
-                       mf2->v1 += indexMap[inMF.v1][1];
-                       mf2->v2 += indexMap[inMF.v2][1];
-                       mf2->v3 += indexMap[inMF.v3][1];
-                       if(inMF.v4) mf2->v4 += indexMap[inMF.v4][1];
-                       
-                       /* mirror UVs if enabled */
-                       if(mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
-                               MTFace *tf = result->getFaceData(result, numFaces, CD_MTFACE);
-                               if(tf) {
-                                       int j;
-                                       for(j = 0; j < 4; ++j) {
-                                               if(mmd->flag & MOD_MIR_MIRROR_U)
-                                                       tf->uv[j][0] = 1.0f - tf->uv[j][0];
-                                               if(mmd->flag & MOD_MIR_MIRROR_V)
-                                                       tf->uv[j][1] = 1.0f - tf->uv[j][1];
-                                       }
-                               }
-                       }
-                       
-                       /* Flip face normal */
-                       SWAP(unsigned int, mf2->v1, mf2->v3);
-                       DM_swap_face_data(result, numFaces, corner_indices);
-                       
-                       test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
-                       numFaces++;
+               ml2 = ml + mp->loopstart + dm->numLoopData;
+               e = ml2[0].e;
+               for (j=0; j<mp->totloop-1; j++) {
+                       ml2[j].e = ml2[j+1].e;
                }
+               ml2[mp->totloop-1].e = e;
+               
+               mp->loopstart += dm->numLoopData;
        }
 
-       if (flip_map) MEM_freeN(flip_map);
-
-       MEM_freeN(indexMap);
+       /*adjust mirrored loop vertex and edge indices*/        
+       ml = CDDM_get_loops(cddm) + dm->numLoopData;
+       for (i=0; i<dm->numLoopData; i++, ml++) {
+               ml->v += dm->numVertData;
+               ml->e += dm->numEdgeData;
+       }
 
-       CDDM_lower_num_verts(result, numVerts);
-       CDDM_lower_num_edges(result, numEdges);
-       CDDM_lower_num_faces(result, numFaces);
+       CDDM_recalc_tesselation(cddm);
+       
+       /*handle vgroup stuff*/
+       if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&cddm->vertData, CD_MDEFORMVERT)) {
+               MDeformVert *dvert = CustomData_get_layer(&cddm->vertData, CD_MDEFORMVERT);
+               int *flip_map= NULL, flip_map_len= 0;
 
-       return result;
+               flip_map= defgroup_flip_map(ob, &flip_map_len, FALSE);
+               
+               for (i=0; i<dm->numVertData; i++, dvert++) {
+                       defvert_flip(dvert, flip_map, flip_map_len);
+               }
+       }
+       
+       if (!(mmd->flag & MOD_MIR_NO_MERGE))
+               cddm = CDDM_merge_verts(cddm, vtargetmap);
+       
+       BLI_array_free(vtargetmap);
+       
+       if (vector_def) MEM_freeN(vector_def);
+       
+       if (dm != origdm) {
+               dm->needsFree = 1;
+               dm->release(dm);
+       }
+       
+       return cddm;
 }
 
 static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
@@ -325,7 +300,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
 }
 
 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
-                                               struct EditMesh *UNUSED(editData),
+                                               struct BMEditMesh *UNUSED(editData),
                                                DerivedMesh *derivedData)
 {
        return applyModifier(md, ob, derivedData, 0, 1);