static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, Object *ob, 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; } 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); } 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; } 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++; } } 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]; } } 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]; 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++; } }