merge with trunk at r31523
[blender.git] / source / blender / modifiers / intern / MOD_array.c
index a6fefbcd8634ef8a8c3bd2cc08a0aedefc0ce2a1..98295ae0d8e6a8aedf1f2d037d83f848248101fc 100644 (file)
@@ -47,6 +47,7 @@
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BKE_object.h"
+#include "BKE_tessmesh.h"
 
 #include "depsgraph_private.h"
 
@@ -151,6 +152,118 @@ static float vertarray_size(MVert *mvert, int numVerts, int axis)
        return max_co - min_co;
 }
 
+/* finds the best possible flipped name. For renaming; check for unique names afterwards */
+/* if strip_number: removes number extensions */
+void vertgroup_flip_name (char *name, int strip_number)
+{
+       int     len;
+       char    prefix[128]={""};   /* The part before the facing */
+       char    suffix[128]={""};   /* The part after the facing */
+       char    replace[128]={""};  /* The replacement string */
+       char    number[128]={""};   /* The number extension string */
+       char    *index=NULL;
+
+       len= strlen(name);
+       if(len<3) return; // we don't do names like .R or .L
+
+       /* We first check the case with a .### extension, let's find the last period */
+       if(isdigit(name[len-1])) {
+               index= strrchr(name, '.'); // last occurrance
+               if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
+                       if(strip_number==0)
+                               strcpy(number, index);
+                       *index= 0;
+                       len= strlen(name);
+               }
+       }
+
+       strcpy (prefix, name);
+
+#define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_')
+
+       /* first case; separator . - _ with extensions r R l L  */
+       if( IS_SEPARATOR(name[len-2]) ) {
+               switch(name[len-1]) {
+                       case 'l':
+                               prefix[len-1]= 0;
+                               strcpy(replace, "r");
+                               break;
+                       case 'r':
+                               prefix[len-1]= 0;
+                               strcpy(replace, "l");
+                               break;
+                       case 'L':
+                               prefix[len-1]= 0;
+                               strcpy(replace, "R");
+                               break;
+                       case 'R':
+                               prefix[len-1]= 0;
+                               strcpy(replace, "L");
+                               break;
+               }
+       }
+       /* case; beginning with r R l L , with separator after it */
+       else if( IS_SEPARATOR(name[1]) ) {
+               switch(name[0]) {
+                       case 'l':
+                               strcpy(replace, "r");
+                               strcpy(suffix, name+1);
+                               prefix[0]= 0;
+                               break;
+                       case 'r':
+                               strcpy(replace, "l");
+                               strcpy(suffix, name+1);
+                               prefix[0]= 0;
+                               break;
+                       case 'L':
+                               strcpy(replace, "R");
+                               strcpy(suffix, name+1);
+                               prefix[0]= 0;
+                               break;
+                       case 'R':
+                               strcpy(replace, "L");
+                               strcpy(suffix, name+1);
+                               prefix[0]= 0;
+                               break;
+               }
+       }
+       else if(len > 5) {
+               /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
+               index = BLI_strcasestr(prefix, "right");
+               if (index==prefix || index==prefix+len-5) {
+                       if(index[0]=='r')
+                               strcpy (replace, "left");
+                       else {
+                               if(index[1]=='I')
+                                       strcpy (replace, "LEFT");
+                               else
+                                       strcpy (replace, "Left");
+                       }
+                       *index= 0;
+                       strcpy (suffix, index+5);
+               }
+               else {
+                       index = BLI_strcasestr(prefix, "left");
+                       if (index==prefix || index==prefix+len-4) {
+                               if(index[0]=='l')
+                                       strcpy (replace, "right");
+                               else {
+                                       if(index[1]=='E')
+                                               strcpy (replace, "RIGHT");
+                                       else
+                                               strcpy (replace, "Right");
+                               }
+                               *index= 0;
+                               strcpy (suffix, index+4);
+                       }
+               }
+       }
+
+#undef IS_SEPARATOR
+
+       sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
+}
+
 typedef struct IndexMapEntry {
        /* the new vert index that this old vert index maps to */
        int new;
@@ -190,45 +303,37 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum)
 }
 
 static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
-                                         struct Scene *scene, Object *ob, DerivedMesh *dm,
-          int initFlags)
+                                         Scene *scene, Object *ob, DerivedMesh *dm,
+                                                                                 int initFlags)
 {
-       int i, j;
+       DerivedMesh *cddm = dm; //copying shouldn't be necassary here, as all modifiers return CDDM's
+       BMEditMesh *em = CDDM_To_BMesh(cddm, NULL);
+       BMOperator op, oldop, weldop;
+       int i, j, indexLen;
        /* offset matrix */
        float offset[4][4];
        float final_offset[4][4];
        float tmp_mat[4][4];
        float length = amd->length;
-       int count = amd->count;
-       int numVerts, numEdges, numFaces;
-       int maxVerts, maxEdges, maxFaces;
+       int count = amd->count, maxVerts;
        int finalVerts, finalEdges, finalFaces;
-       DerivedMesh *result, *start_cap = NULL, *end_cap = NULL;
-       MVert *mvert, *src_mvert;
-       MEdge *medge;
-       MFace *mface;
-
-       IndexMapEntry *indexMap;
-
-       EdgeHash *edges;
+       int *indexMap = NULL;
+       DerivedMesh *start_cap = NULL, *end_cap = NULL;
+       MVert *src_mvert;
 
        /* need to avoid infinite recursion here */
        if(amd->start_cap && amd->start_cap != ob)
-               start_cap = amd->start_cap->derivedFinal;
+               start_cap = mesh_get_derived_final(scene, amd->start_cap, CD_MASK_MESH);
        if(amd->end_cap && amd->end_cap != ob)
-               end_cap = amd->end_cap->derivedFinal;
+               end_cap = mesh_get_derived_final(scene, amd->end_cap, CD_MASK_MESH);
 
        unit_m4(offset);
 
-       indexMap = MEM_callocN(sizeof(*indexMap) * dm->getNumVerts(dm),
-                                  "indexmap");
-
-       src_mvert = dm->getVertArray(dm);
-
-       maxVerts = dm->getNumVerts(dm);
+       src_mvert = cddm->getVertArray(dm);
+       maxVerts = cddm->getNumVerts(dm);
 
        if(amd->offset_type & MOD_ARR_OFF_CONST)
-               add_v3_v3(offset[3], amd->offset);
+               add_v3_v3v3(offset[3], offset[3], amd->offset);
        if(amd->offset_type & MOD_ARR_OFF_RELATIVE) {
                for(j = 0; j < 3; j++)
                        offset[3][j] += amd->scale[j] * vertarray_size(src_mvert,
@@ -246,7 +351,7 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
 
                mul_serie_m4(result_mat, offset,
                                 obinv, amd->offset_ob->obmat,
-        NULL, NULL, NULL, NULL, NULL);
+                                                                NULL, NULL, NULL, NULL, NULL);
                copy_m4_m4(offset, result_mat);
        }
 
@@ -255,10 +360,10 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
                if(cu) {
                        float tmp_mat[3][3];
                        float scale;
-                       
+
                        object_to_mat3(amd->curve_ob, tmp_mat);
                        scale = mat3_to_scale(tmp_mat);
-                               
+
                        if(!cu->path) {
                                cu->flag |= CU_PATH; // needed for path & bevlist
                                makeDispListCurveTypes(scene, amd->curve_ob, 0);
@@ -271,8 +376,9 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
        /* calculate the maximum number of copies which will fit within the
        prescribed length */
        if(amd->fit_type == MOD_ARR_FITLENGTH
-                 || amd->fit_type == MOD_ARR_FITCURVE) {
-               float dist = sqrt(dot_v3v3(offset[3], offset[3]));
+                 || amd->fit_type == MOD_ARR_FITCURVE)
+       {
+               float dist = sqrt(INPR(offset[3], offset[3]));
 
                if(dist > 1e-6f)
                        /* this gives length = first copy start to last copy end
@@ -281,452 +387,125 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
                else
                        /* if the offset has no translation, just make one copy */
                        count = 1;
-                 }
+       }
 
-                 if(count < 1)
-                         count = 1;
+       if(count < 1)
+               count = 1;
 
        /* allocate memory for count duplicates (including original) plus
                  * start and end caps
        */
-                 finalVerts = dm->getNumVerts(dm) * count;
-                 finalEdges = dm->getNumEdges(dm) * count;
-                 finalFaces = dm->getNumFaces(dm) * count;
-                 if(start_cap) {
-                         finalVerts += start_cap->getNumVerts(start_cap);
-                         finalEdges += start_cap->getNumEdges(start_cap);
-                         finalFaces += start_cap->getNumFaces(start_cap);
-                 }
-                 if(end_cap) {
-                         finalVerts += end_cap->getNumVerts(end_cap);
-                         finalEdges += end_cap->getNumEdges(end_cap);
-                         finalFaces += end_cap->getNumFaces(end_cap);
-                 }
-                 result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces);
-
-                 /* calculate the offset matrix of the final copy (for merging) */ 
-                 unit_m4(final_offset);
-
-                 for(j=0; j < count - 1; j++) {
-                         mul_m4_m4m4(tmp_mat, final_offset, offset);
-                         copy_m4_m4(final_offset, tmp_mat);
-                 }
-
-                 numVerts = numEdges = numFaces = 0;
-                 mvert = CDDM_get_verts(result);
-
-                 for (i = 0; i < maxVerts; i++) {
-                         indexMap[i].merge = -1; /* default to no merge */
-                         indexMap[i].merge_final = 0; /* default to no merge */
-                 }
-
-                 for (i = 0; i < maxVerts; i++) {
-                         MVert *inMV;
-                         MVert *mv = &mvert[numVerts];
-                         MVert *mv2;
-                         float co[3];
-
-                         inMV = &src_mvert[i];
-
-                         DM_copy_vert_data(dm, result, i, numVerts, 1);
-                         *mv = *inMV;
-                         numVerts++;
-
-                         indexMap[i].new = numVerts - 1;
-
-                         copy_v3_v3(co, mv->co);
-               
-               /* Attempts to merge verts from one duplicate with verts from the
-                         * next duplicate which are closer than amd->merge_dist.
-                         * Only the first such vert pair is merged.
-                         * If verts are merged in the first duplicate pair, they are merged
-                         * in all pairs.
-               */
-                         if((count > 1) && (amd->flags & MOD_ARR_MERGE)) {
-                                 float tmp_co[3];
-                                 mul_v3_m4v3(tmp_co, offset, mv->co);
-
-                                 for(j = 0; j < maxVerts; j++) {
-                                         /* if vertex already merged, don't use it */
-                                         if( indexMap[j].merge != -1 ) continue;
-
-                                         inMV = &src_mvert[j];
-                                         /* if this vert is within merge limit, merge */
-                                         if(compare_len_v3v3(tmp_co, inMV->co, amd->merge_dist)) {
-                                                 indexMap[i].merge = j;
-
-                                                 /* test for merging with final copy of merge target */
-                                                 if(amd->flags & MOD_ARR_MERGEFINAL) {
-                                                         copy_v3_v3(tmp_co, inMV->co);
-                                                         inMV = &src_mvert[i];
-                                                         mul_m4_v3(final_offset, tmp_co);
-                                                         if(compare_len_v3v3(tmp_co, inMV->co, amd->merge_dist))
-                                                                 indexMap[i].merge_final = 1;
-                                                 }
-                                                 break;
-                                         }
-                                 }
-                         }
-
-                         /* if no merging, generate copies of this vert */
-                         if(indexMap[i].merge < 0) {
-                                 for(j=0; j < count - 1; j++) {
-                                         mv2 = &mvert[numVerts];
-
-                                         DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1);
-                                         *mv2 = *mv;
-                                         numVerts++;
-
-                                         mul_m4_v3(offset, co);
-                                         copy_v3_v3(mv2->co, co);
-                                 }
-                         } else if(indexMap[i].merge != i && indexMap[i].merge_final) {
-                       /* if this vert is not merging with itself, and it is merging
-                                 * with the final copy of its merge target, remove the first copy
-                       */
-                                 numVerts--;
-                                 DM_free_vert_data(result, numVerts, 1);
-                         }
-                 }
-
-                 /* make a hashtable so we can avoid duplicate edges from merging */
-                 edges = BLI_edgehash_new();
-
-                 maxEdges = dm->getNumEdges(dm);
-                 medge = CDDM_get_edges(result);
-                 for(i = 0; i < maxEdges; i++) {
-                         MEdge inMED;
-                         MEdge med;
-                         MEdge *med2;
-                         int vert1, vert2;
-
-                         dm->getEdge(dm, i, &inMED);
-
-                         med = inMED;
-                         med.v1 = indexMap[inMED.v1].new;
-                         med.v2 = indexMap[inMED.v2].new;
-
-               /* if vertices are to be merged with the final copies of their
-                         * merge targets, calculate that final copy
-               */
-                         if(indexMap[inMED.v1].merge_final) {
-                                 med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge,
-                                                 count - 1);
-                         }
-                         if(indexMap[inMED.v2].merge_final) {
-                                 med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge,
-                                                 count - 1);
-                         }
-
-                         if(med.v1 == med.v2) continue;
-
-                         if (initFlags) {
-                                 med.flag |= ME_EDGEDRAW | ME_EDGERENDER;
-                         }
-
-                         if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) {
-                                 DM_copy_edge_data(dm, result, i, numEdges, 1);
-                                 medge[numEdges] = med;
-                                 numEdges++;
-
-                                 BLI_edgehash_insert(edges, med.v1, med.v2, NULL);
-                         }
-
-                         for(j = 1; j < count; j++)
-                         {
-                                 vert1 = calc_mapping(indexMap, inMED.v1, j);
-                                 vert2 = calc_mapping(indexMap, inMED.v2, j);
-                                 /* avoid duplicate edges */
-                                 if(!BLI_edgehash_haskey(edges, vert1, vert2)) {
-                                         med2 = &medge[numEdges];
-
-                                         DM_copy_edge_data(dm, result, i, numEdges, 1);
-                                         *med2 = med;
-                                         numEdges++;
-
-                                         med2->v1 = vert1;
-                                         med2->v2 = vert2;
-
-                                         BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL);
-                                 }
-                         }
-                 }
-
-                 maxFaces = dm->getNumFaces(dm);
-                 mface = CDDM_get_faces(result);
-                 for (i=0; i < maxFaces; i++) {
-                         MFace inMF;
-                         MFace *mf = &mface[numFaces];
-
-                         dm->getFace(dm, i, &inMF);
-
-                         DM_copy_face_data(dm, result, i, numFaces, 1);
-                         *mf = inMF;
-
-                         mf->v1 = indexMap[inMF.v1].new;
-                         mf->v2 = indexMap[inMF.v2].new;
-                         mf->v3 = indexMap[inMF.v3].new;
-                         if(inMF.v4)
-                                 mf->v4 = indexMap[inMF.v4].new;
-
-               /* if vertices are to be merged with the final copies of their
-                         * merge targets, calculate that final copy
-               */
-                         if(indexMap[inMF.v1].merge_final)
-                                 mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-1);
-                         if(indexMap[inMF.v2].merge_final)
-                                 mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-1);
-                         if(indexMap[inMF.v3].merge_final)
-                                 mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-1);
-                         if(inMF.v4 && indexMap[inMF.v4].merge_final)
-                                 mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-1);
-
-                         if(test_index_face(mf, &result->faceData, numFaces, inMF.v4?4:3) < 3)
-                                 continue;
-
-                         numFaces++;
-
-                         /* if the face has fewer than 3 vertices, don't create it */
-                         if(mf->v3 == 0 || (mf->v1 && (mf->v1 == mf->v3 || mf->v1 == mf->v4))) {
-                                 numFaces--;
-                                 DM_free_face_data(result, numFaces, 1);
-                         }
-
-                         for(j = 1; j < count; j++)
-                         {
-                                 MFace *mf2 = &mface[numFaces];
-
-                                 DM_copy_face_data(dm, result, i, numFaces, 1);
-                                 *mf2 = *mf;
-
-                                 mf2->v1 = calc_mapping(indexMap, inMF.v1, j);
-                                 mf2->v2 = calc_mapping(indexMap, inMF.v2, j);
-                                 mf2->v3 = calc_mapping(indexMap, inMF.v3, j);
-                                 if (inMF.v4)
-                                         mf2->v4 = calc_mapping(indexMap, inMF.v4, j);
-
-                                 test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
-                                 numFaces++;
-
-                                 /* if the face has fewer than 3 vertices, don't create it */
-                                 if(mf2->v3 == 0 || (mf2->v1 && (mf2->v1 == mf2->v3 || mf2->v1 ==
-                                                                mf2->v4))) {
-                                         numFaces--;
-                                         DM_free_face_data(result, numFaces, 1);
-                                                                }
-                         }
-                 }
-
-                 /* add start and end caps */
-                 if(start_cap) {
-                         float startoffset[4][4];
-                         MVert *cap_mvert;
-                         MEdge *cap_medge;
-                         MFace *cap_mface;
-                         int *origindex;
-                         int *vert_map;
-                         int capVerts, capEdges, capFaces;
-
-                         capVerts = start_cap->getNumVerts(start_cap);
-                         capEdges = start_cap->getNumEdges(start_cap);
-                         capFaces = start_cap->getNumFaces(start_cap);
-                         cap_mvert = start_cap->getVertArray(start_cap);
-                         cap_medge = start_cap->getEdgeArray(start_cap);
-                         cap_mface = start_cap->getFaceArray(start_cap);
-
-                         invert_m4_m4(startoffset, offset);
-
-                         vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
-                                         "arrayModifier_doArray vert_map");
-
-                         origindex = result->getVertDataArray(result, CD_ORIGINDEX);
-                         for(i = 0; i < capVerts; i++) {
-                                 MVert *mv = &cap_mvert[i];
-                                 short merged = 0;
-
-                                 if(amd->flags & MOD_ARR_MERGE) {
-                                         float tmp_co[3];
-                                         MVert *in_mv;
-                                         int j;
-
-                                         copy_v3_v3(tmp_co, mv->co);
-                                         mul_m4_v3(startoffset, tmp_co);
-
-                                         for(j = 0; j < maxVerts; j++) {
-                                                 in_mv = &src_mvert[j];
-                                                 /* if this vert is within merge limit, merge */
-                                                 if(compare_len_v3v3(tmp_co, in_mv->co, amd->merge_dist)) {
-                                                         vert_map[i] = calc_mapping(indexMap, j, 0);
-                                                         merged = 1;
-                                                         break;
-                                                 }
-                                         }
-                                 }
-
-                                 if(!merged) {
-                                         DM_copy_vert_data(start_cap, result, i, numVerts, 1);
-                                         mvert[numVerts] = *mv;
-                                         mul_m4_v3(startoffset, mvert[numVerts].co);
-                                         origindex[numVerts] = ORIGINDEX_NONE;
-
-                                         vert_map[i] = numVerts;
-
-                                         numVerts++;
-                                 }
-                         }
-                         origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
-                         for(i = 0; i < capEdges; i++) {
-                                 int v1, v2;
-
-                                 v1 = vert_map[cap_medge[i].v1];
-                                 v2 = vert_map[cap_medge[i].v2];
-
-                                 if(!BLI_edgehash_haskey(edges, v1, v2)) {
-                                         DM_copy_edge_data(start_cap, result, i, numEdges, 1);
-                                         medge[numEdges] = cap_medge[i];
-                                         medge[numEdges].v1 = v1;
-                                         medge[numEdges].v2 = v2;
-                                         origindex[numEdges] = ORIGINDEX_NONE;
-
-                                         numEdges++;
-                                 }
-                         }
-                         origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
-                         for(i = 0; i < capFaces; i++) {
-                                 DM_copy_face_data(start_cap, result, i, numFaces, 1);
-                                 mface[numFaces] = cap_mface[i];
-                                 mface[numFaces].v1 = vert_map[mface[numFaces].v1];
-                                 mface[numFaces].v2 = vert_map[mface[numFaces].v2];
-                                 mface[numFaces].v3 = vert_map[mface[numFaces].v3];
-                                 if(mface[numFaces].v4) {
-                                         mface[numFaces].v4 = vert_map[mface[numFaces].v4];
-
-                                         test_index_face(&mface[numFaces], &result->faceData,
-                                                                         numFaces, 4);
-                                 }
-                                 else
-                                 {
-                                         test_index_face(&mface[numFaces], &result->faceData,
-                                                                         numFaces, 3);
-                                 }
-
-                                 origindex[numFaces] = ORIGINDEX_NONE;
-
-                                 numFaces++;
-                         }
-
-                         MEM_freeN(vert_map);
-                         start_cap->release(start_cap);
-                 }
-
-                 if(end_cap) {
-                         float endoffset[4][4];
-                         MVert *cap_mvert;
-                         MEdge *cap_medge;
-                         MFace *cap_mface;
-                         int *origindex;
-                         int *vert_map;
-                         int capVerts, capEdges, capFaces;
-
-                         capVerts = end_cap->getNumVerts(end_cap);
-                         capEdges = end_cap->getNumEdges(end_cap);
-                         capFaces = end_cap->getNumFaces(end_cap);
-                         cap_mvert = end_cap->getVertArray(end_cap);
-                         cap_medge = end_cap->getEdgeArray(end_cap);
-                         cap_mface = end_cap->getFaceArray(end_cap);
-
-                         mul_m4_m4m4(endoffset, final_offset, offset);
-
-                         vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
-                                         "arrayModifier_doArray vert_map");
-
-                         origindex = result->getVertDataArray(result, CD_ORIGINDEX);
-                         for(i = 0; i < capVerts; i++) {
-                                 MVert *mv = &cap_mvert[i];
-                                 short merged = 0;
-
-                                 if(amd->flags & MOD_ARR_MERGE) {
-                                         float tmp_co[3];
-                                         MVert *in_mv;
-                                         int j;
-
-                                         copy_v3_v3(tmp_co, mv->co);
-                                         mul_m4_v3(offset, tmp_co);
-
-                                         for(j = 0; j < maxVerts; j++) {
-                                                 in_mv = &src_mvert[j];
-                                                 /* if this vert is within merge limit, merge */
-                                                 if(compare_len_v3v3(tmp_co, in_mv->co, amd->merge_dist)) {
-                                                         vert_map[i] = calc_mapping(indexMap, j, count - 1);
-                                                         merged = 1;
-                                                         break;
-                                                 }
-                                         }
-                                 }
-
-                                 if(!merged) {
-                                         DM_copy_vert_data(end_cap, result, i, numVerts, 1);
-                                         mvert[numVerts] = *mv;
-                                         mul_m4_v3(endoffset, mvert[numVerts].co);
-                                         origindex[numVerts] = ORIGINDEX_NONE;
-
-                                         vert_map[i] = numVerts;
-
-                                         numVerts++;
-                                 }
-                         }
-                         origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
-                         for(i = 0; i < capEdges; i++) {
-                                 int v1, v2;
-
-                                 v1 = vert_map[cap_medge[i].v1];
-                                 v2 = vert_map[cap_medge[i].v2];
-
-                                 if(!BLI_edgehash_haskey(edges, v1, v2)) {
-                                         DM_copy_edge_data(end_cap, result, i, numEdges, 1);
-                                         medge[numEdges] = cap_medge[i];
-                                         medge[numEdges].v1 = v1;
-                                         medge[numEdges].v2 = v2;
-                                         origindex[numEdges] = ORIGINDEX_NONE;
-
-                                         numEdges++;
-                                 }
-                         }
-                         origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
-                         for(i = 0; i < capFaces; i++) {
-                                 DM_copy_face_data(end_cap, result, i, numFaces, 1);
-                                 mface[numFaces] = cap_mface[i];
-                                 mface[numFaces].v1 = vert_map[mface[numFaces].v1];
-                                 mface[numFaces].v2 = vert_map[mface[numFaces].v2];
-                                 mface[numFaces].v3 = vert_map[mface[numFaces].v3];
-                                 if(mface[numFaces].v4) {
-                                         mface[numFaces].v4 = vert_map[mface[numFaces].v4];
-
-                                         test_index_face(&mface[numFaces], &result->faceData,
-                                                                         numFaces, 4);
-                                 }
-                                 else
-                                 {
-                                         test_index_face(&mface[numFaces], &result->faceData,
-                                                                         numFaces, 3);
-                                 }
-                                 origindex[numFaces] = ORIGINDEX_NONE;
-
-                                 numFaces++;
-                         }
-
-                         MEM_freeN(vert_map);
-                         end_cap->release(end_cap);
-                 }
-
-                 BLI_edgehash_free(edges, NULL);
-                 MEM_freeN(indexMap);
-
-                 CDDM_lower_num_verts(result, numVerts);
-                 CDDM_lower_num_edges(result, numEdges);
-                 CDDM_lower_num_faces(result, numFaces);
-
-                 return result;
+       finalVerts = dm->getNumVerts(dm) * count;
+       finalEdges = dm->getNumEdges(dm) * count;
+       finalFaces = dm->getNumFaces(dm) * count;
+       if(start_cap) {
+               finalVerts += start_cap->getNumVerts(start_cap);
+               finalEdges += start_cap->getNumEdges(start_cap);
+               finalFaces += start_cap->getNumFaces(start_cap);
+       }
+       if(end_cap) {
+               finalVerts += end_cap->getNumVerts(end_cap);
+               finalEdges += end_cap->getNumEdges(end_cap);
+               finalFaces += end_cap->getNumFaces(end_cap);
+       }
+
+       /* calculate the offset matrix of the final copy (for merging) */
+       unit_m4(final_offset);
+
+       for(j=0; j < count - 1; j++) {
+               mul_m4_m4m4(tmp_mat, final_offset, offset);
+               copy_m4_m4(final_offset, tmp_mat);
+       }
+
+       BMO_Init_Op(&weldop, "weldverts");
+       BMO_InitOpf(em->bm, &op, "dupe geom=%avef");
+       oldop = op;
+       for (j=0; j < count; j++) {
+               BMVert *v, *v2;
+               BMOpSlot *s1;
+               BMOpSlot *s2;
+
+               BMO_InitOpf(em->bm, &op, "dupe geom=%s", &oldop, j==0 ? "geom" : "newout");
+               BMO_Exec_Op(em->bm, &op);
+
+               s1 = BMO_GetSlot(&op, "geom");
+               s2 = BMO_GetSlot(&op, "newout");
+
+               BMO_CallOpf(em->bm, "transform mat=%m4 verts=%s", offset, &op, "newout");
+
+               #define _E(s, i) ((BMVert**)(s)->data.buf)[i]
+
+               /*calculate merge mapping*/
+               if (j == 0) {
+                       BMOperator findop;
+                       BMOIter oiter;
+                       BMVert *v, *v2;
+                       BMHeader *h;
+
+                       BMO_InitOpf(em->bm, &findop,
+                               "finddoubles verts=%av dist=%f keepverts=%s",
+                               amd->merge_dist, &op, "geom");
+
+                       i = 0;
+                       BMO_ITER(h, &oiter, em->bm, &op, "geom", BM_ALL) {
+                               BMINDEX_SET(h, i);
+                               i++;
+                       }
+
+                       BMO_ITER(h, &oiter, em->bm, &op, "newout", BM_ALL) {
+                               BMINDEX_SET(h, i);
+                               i++;
+                       }
+
+                       BMO_Exec_Op(em->bm, &findop);
+
+                       indexLen = i;
+                       indexMap = MEM_callocN(sizeof(int)*indexLen, "indexMap");
+
+                       /*element type argument doesn't do anything here*/
+                       BMO_ITER(v, &oiter, em->bm, &findop, "targetmapout", 0) {
+                               v2 = BMO_IterMapValp(&oiter);
+
+                               indexMap[BMINDEX_GET(v)] = BMINDEX_GET(v2)+1;
+                       }
+
+                       BMO_Finish_Op(em->bm, &findop);
+               }
+
+               /*generate merge mappping using index map.  we do this by using the
+                 operator slots as lookup arrays.*/
+               #define E(i) (i) < s1->len ? _E(s1, i) : _E(s2, (i)-s1->len)
+
+               for (i=0; i<indexLen; i++) {
+                       if (!indexMap[i]) continue;
+
+                       v = E(i);
+                       v2 = E(indexMap[i]-1);
+
+                       BMO_Insert_MapPointer(em->bm, &weldop, "targetmap", v, v2);
+               }
+
+               #undef E
+               #undef _E
+
+               BMO_Finish_Op(em->bm, &oldop);
+               oldop = op;
+       }
+
+       if (j > 0) BMO_Finish_Op(em->bm, &op);
+
+       if (amd->flags & MOD_ARR_MERGE)
+               BMO_Exec_Op(em->bm, &weldop);
+
+       BMO_Finish_Op(em->bm, &weldop);
+
+       BMEdit_RecalcTesselation(em);
+       cddm = CDDM_from_BMEditMesh(em, NULL);
+
+       BMEdit_Free(em);
+       MEM_freeN(indexMap);
+
+       return cddm;
 }
 
 static DerivedMesh *applyModifier(
@@ -738,8 +517,8 @@ static DerivedMesh *applyModifier(
 
        result = arrayModifier_doArray(amd, md->scene, ob, derivedData, 0);
 
-       if(result != derivedData)
-               CDDM_calc_normals(result);
+       //if(result != derivedData)
+       //      CDDM_calc_normals(result);
 
        return result;
 }