svn merge -r39286:39385 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / modifiers / intern / MOD_mirror.c
index 7cde87b20d98a8b68fe44da8d29ae7f627bdf244..d93d7aecb5dfd00014eb72c6b60102bab1c7925f 100644 (file)
 *
 */
 
-/** \file blender/modifiers/intern/MOD_mirror.c
- *  \ingroup modifiers
- */
-
-
 #include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
 
 #include "BLI_math.h"
-#include "BLI_utildefines.h"
+#include "BLI_smallhash.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;
@@ -69,7 +64,7 @@ static void copyData(ModifierData *md, ModifierData *target)
        tmmd->axis = mmd->axis;
        tmmd->flag = mmd->flag;
        tmmd->tolerance = mmd->tolerance;
-       tmmd->mirror_ob = mmd->mirror_ob;
+       tmmd->mirror_ob = mmd->mirror_ob;;
 }
 
 static void foreachObjectLink(
@@ -78,14 +73,13 @@ static void foreachObjectLink(
                 void *userData)
 {
        MirrorModifierData *mmd = (MirrorModifierData*) md;
-
-       walk(userData, ob, &mmd->mirror_ob);
+       
+       if (mmd->mirror_ob)
+               walk(userData, ob, &mmd->mirror_ob);
 }
 
-static void updateDepgraph(ModifierData *md, DagForest *forest,
-                                               struct Scene *UNUSED(scene),
-                                               Object *UNUSED(ob),
-                                               DagNode *obNode)
+static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+                                         Object *UNUSED(ob), DagNode *obNode)
 {
        MirrorModifierData *mmd = (MirrorModifierData*) md;
 
@@ -97,195 +91,172 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
        }
 }
 
-static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
+
+/* Mirror */
+#define VERT_NEW       1
+
+void vertgroup_flip_name (char *name, int strip_number);
+DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
                Object *ob,
                DerivedMesh *dm,
-               int initFlags,
+               int UNUSED(initFlags),
                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;
-       int do_vgroup_mirr= (mmd->flag & MOD_MIR_VGROUP);
-       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, 0);
-               if(flip_map == NULL)
-                       do_vgroup_mirr= 0;
+       DerivedMesh *cddm, *origdm;
+       bDeformGroup *def, *defb;
+       bDeformGroup **vector_def = NULL;
+       MVert *mv;
+       MEdge *me;
+       MLoop *ml;
+       MPoly *mp;
+       float mtx[4][4];
+       int i, j, *vtargetmap = NULL;
+       BLI_array_declare(vtargetmap);
+       int vector_size=0, a, b, totshape;
+       
+       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;
+               }
        }
 
        if (mmd->mirror_ob) {
-               float obinv[4][4];
-               
-               invert_m4_m4(obinv, mmd->mirror_ob->obmat);
-               mul_m4_m4m4(mtx, ob->obmat, obinv);
-               invert_m4_m4(imtx, mtx);
-       }
+               float mtx2[4][4];
 
-       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);
+               invert_m4_m4(mtx2, mmd->mirror_ob->obmat);
+               mul_m4_m4m4(mtx, ob->obmat, mtx2);
+       } else {
+               unit_m4(mtx);
+       }
+       
+       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*/
+       mv = CDDM_get_verts(cddm) + dm->numVertData;
+       for (i=0; i<dm->numVertData; i++, mv++) {
+               mv->co[axis] = -mv->co[axis];
+               if (fabs(mv->co[axis]) < tolerance) {
+                       BLI_array_append(vtargetmap, i+dm->numVertData);
+               } else BLI_array_append(vtargetmap, -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++) {
+                       cos[i][axis] = -cos[i][axis];
                }
+       }
+       
+       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;
                
-               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;
-               numVerts++;
+               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);
+               }
                
-               indexMap[i][0] = numVerts - 1;
-               indexMap[i][1] = !isShared;
-               //
-               if(isShared ) {
-                       co[axis] = 0;
-                       if (mmd->mirror_ob) {
-                               mul_m4_v3(imtx, co);
-                       }
-                       copy_v3_v3(mv->co, co);
-                       
-                       mv->flag |= ME_VERT_MERGED;
-               } 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);
-                               }
-                       }
-
-                       numVerts++;
+               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;
        }
 
-       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(initFlags)
-                       med->flag |= ME_EDGEDRAW | ME_EDGERENDER;
-               
-               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];
-               }
+       /*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;
        }
 
-       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++;
-               
-               mf->v1 = indexMap[inMF.v1][0];
-               mf->v2 = indexMap[inMF.v2][0];
-               mf->v3 = indexMap[inMF.v3][0];
-               mf->v4 = indexMap[inMF.v4][0];
+       CDDM_recalc_tesselation(cddm, 1);
+       
+       /*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);
                
-               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];
+               for (i=0; i<dm->numVertData; i++, dvert++) {
+                       for(j = 0; j < dvert->totweight; ++j) {
+                               char tmpname[32];
+
+                               if(dvert->dw[j].def_nr < 0 ||
+                                  dvert->dw[j].def_nr >= vector_size)
+                                       continue;
+
+                               def = vector_def[dvert->dw[j].def_nr];
+                               strcpy(tmpname, def->name);
+                               vertgroup_flip_name(tmpname,0);
+
+                               for(b = 0, defb = ob->defbase.first; defb;
+                                       defb = defb->next, b++)
+                               {
+                                       if(!strcmp(defb->name, tmpname))
+                                       {
+                                               dvert->dw[j].def_nr = b;
+                                               break;
                                        }
                                }
                        }
-                       
-                       /* Flip face normal */
-                       SWAP(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++;
                }
        }
-
-       if (flip_map) MEM_freeN(flip_map);
-
-       MEM_freeN(indexMap);
-
-       CDDM_lower_num_verts(result, numVerts);
-       CDDM_lower_num_edges(result, numEdges);
-       CDDM_lower_num_faces(result, numFaces);
-
-       return result;
+       
+       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,
@@ -312,10 +283,9 @@ static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
        return result;
 }
 
-static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
-                                               DerivedMesh *derivedData,
-                                               int UNUSED(useRenderParams),
-                                               int UNUSED(isFinalCalc))
+static DerivedMesh *applyModifier(
+               ModifierData *md, Object *ob, DerivedMesh *derivedData,
+  int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
 {
        DerivedMesh *result;
        MirrorModifierData *mmd = (MirrorModifierData*) md;
@@ -328,9 +298,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
        return result;
 }
 
-static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
-                                               struct EditMesh *UNUSED(editData),
-                                               DerivedMesh *derivedData)
+static DerivedMesh *applyModifierEM(
+               ModifierData *md, Object *ob, struct BMEditMesh *UNUSED(editData),
+  DerivedMesh *derivedData)
 {
        return applyModifier(md, ob, derivedData, 0, 1);
 }