part 1 of cleaning up my little array macro library to be a formal API. also removed...
[blender.git] / source / blender / blenkernel / intern / modifiers_bmesh.c
1 /*
2 * $Id: modifier_bmesh.c 20831 2009-06-12 14:02:37Z joeedh $
3 *
4 * ***** BEGIN GPL LICENSE BLOCK *****
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software  Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 *
20 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
21 * All rights reserved.
22 *
23 * Contributor(s): Joseph Eagar
24 *
25 * ***** END GPL LICENSE BLOCK *****
26 *
27 * Modifier stack implementation.
28 *
29 * BKE_modifier.h contains the function prototypes for this file.
30 *
31 */
32
33 #include "string.h"
34 #include "stdarg.h"
35 #include "math.h"
36 #include "float.h"
37 #include "ctype.h"
38
39 #include "BLI_arithb.h"
40 #include "BLI_blenlib.h"
41 #include "BLI_kdopbvh.h"
42 #include "BLI_kdtree.h"
43 #include "BLI_linklist.h"
44 #include "BLI_rand.h"
45 #include "BLI_edgehash.h"
46 #include "BLI_ghash.h"
47 #include "BLI_memarena.h"
48 #include "BLI_cellalloc.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "DNA_action_types.h"
53 #include "DNA_armature_types.h"
54 #include "DNA_camera_types.h"
55 #include "DNA_cloth_types.h"
56 #include "DNA_curve_types.h"
57 #include "DNA_effect_types.h"
58 #include "DNA_material_types.h"
59 #include "DNA_mesh_types.h"
60 #include "DNA_meshdata_types.h"
61 #include "DNA_modifier_types.h"
62 #include "DNA_object_types.h"
63 #include "DNA_object_force.h"
64 #include "DNA_particle_types.h"
65 #include "DNA_scene_types.h"
66 #include "DNA_texture_types.h"
67
68 #include "BLI_editVert.h"
69 #include "BLI_array.h"
70
71 #include "BKE_main.h"
72 #include "BKE_anim.h"
73 #include "BKE_bmesh.h"
74 // XXX #include "BKE_booleanops.h"
75 #include "BKE_cloth.h"
76 #include "BKE_collision.h"
77 #include "BKE_cdderivedmesh.h"
78 #include "BKE_curve.h"
79 #include "BKE_customdata.h"
80 #include "BKE_DerivedMesh.h"
81 #include "BKE_displist.h"
82 #include "BKE_fluidsim.h"
83 #include "BKE_global.h"
84 #include "BKE_multires.h"
85 #include "BKE_lattice.h"
86 #include "BKE_library.h"
87 #include "BKE_material.h"
88 #include "BKE_mesh.h"
89 #include "BKE_modifier.h"
90 #include "BKE_object.h"
91 #include "BKE_particle.h"
92 #include "BKE_pointcache.h"
93 #include "BKE_softbody.h"
94 #include "BKE_subsurf.h"
95 #include "BKE_texture.h"
96 #include "BKE_utildefines.h"
97 #include "BKE_tessmesh.h"
98
99 #include "depsgraph_private.h"
100 #include "BKE_deform.h"
101 #include "BKE_shrinkwrap.h"
102 #include "BKE_simple_deform.h"
103
104 #include "CCGSubSurf.h"
105 #include "RE_shader_ext.h"
106 #include "LOD_decimation.h"
107
108 /*converts a cddm to a BMEditMesh.  if existing is non-NULL, the
109   new geometry will be put in there.*/
110 BMEditMesh *CDDM_To_BMesh(DerivedMesh *dm, BMEditMesh *existing)
111 {
112         int allocsize[4] = {512, 512, 2048, 512};
113         BMesh *bm, bmold; /*bmold is for storing old customdata layout*/
114         BMEditMesh *em = existing;
115         MVert *mv, *mvert;
116         MEdge *me, *medge;
117         DMFaceIter *dfiter;
118         DMLoopIter *dliter;
119         BMVert *v, **vtable, **verts=NULL;
120         BMEdge *e, **etable, **edges=NULL;
121         BMFace *f;
122         BMIter liter;
123         BLI_array_declare(verts);
124         BLI_array_declare(edges);
125         int numTex, numCol;
126         int i, j, k, totvert, totedge, totface;
127         
128         if (em) bm = em->bm;
129         else bm = BM_Make_Mesh(allocsize);
130
131         bmold = *bm;
132
133         /*merge custom data layout*/
134         CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT);
135         CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_EDGE);
136         CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_LOOP);
137         CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_FACE);
138
139         /*needed later*/
140         numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
141         numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
142
143         totvert = dm->getNumVerts(dm);
144         totedge = dm->getNumEdges(dm);
145         totface = dm->getNumFaces(dm);
146
147         vtable = MEM_callocN(sizeof(void**)*totvert, "vert table in BMDM_Copy");
148         etable = MEM_callocN(sizeof(void**)*totedge, "edge table in BMDM_Copy");
149
150         /*do verts*/
151         mv = mvert = dm->dupVertArray(dm);
152         for (i=0; i<totvert; i++, mv++) {
153                 v = BM_Make_Vert(bm, mv->co, NULL);
154                 
155                 v->bweight = mv->bweight;
156                 VECCOPY(v->no, mv->no);
157                 v->head.flag = MEFlags_To_BMFlags(mv->flag, BM_VERT);
158
159                 CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data);
160                 vtable[i] = v;
161         }
162         MEM_freeN(mvert);
163
164         /*do edges*/
165         me = medge = dm->dupEdgeArray(dm);
166         for (i=0; i<totedge; i++, me++) {
167                 e = BM_Make_Edge(bm, vtable[me->v1], vtable[me->v2], NULL, 0);
168
169                 e->bweight = me->bweight;
170                 e->crease = me->crease;
171                 e->head.flag = MEFlags_To_BMFlags(me->flag, BM_EDGE);
172
173                 CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data);
174                 etable[i] = e;
175         }
176         MEM_freeN(medge);
177         
178         /*do faces*/
179         k = 0;
180         dfiter = dm->newFaceIter(dm);
181         for (; !dfiter->done; dfiter->step(dfiter)) {
182                 BMLoop *l;
183
184                 BLI_array_empty(verts);
185                 BLI_array_empty(edges);
186
187                 dliter = dfiter->getLoopsIter(dfiter);
188                 for (j=0; !dliter->done; dliter->step(dliter), j++) {
189                         BLI_array_growone(verts);
190                         BLI_array_growone(edges);
191
192                         verts[j] = vtable[dliter->vindex];
193                         edges[j] = etable[dliter->eindex];
194                 }
195
196                 if (j < 2)
197                         break;
198                 
199                 f = BM_Make_Ngon(bm, verts[0], verts[1], edges, dfiter->len, 0);
200
201                 if (!f) 
202                         continue;
203
204                 f->head.flag = MEFlags_To_BMFlags(dfiter->flags, BM_FACE);
205                 f->mat_nr = dfiter->mat_nr;
206
207                 dliter = dfiter->getLoopsIter(dfiter);
208                 l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
209                 for (j=0; l; l=BMIter_Step(&liter)) {
210                         CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, k, &l->head.data);
211                         k += 1;
212                 }
213
214                 CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, 
215                         dfiter->index, &f->head.data);
216         }
217         dfiter->free(dfiter);
218
219         MEM_freeN(vtable);
220         MEM_freeN(etable);
221         
222         BLI_array_free(verts);
223         BLI_array_free(edges);
224
225         if (!em) em = BMEdit_Create(bm);
226         else BMEdit_RecalcTesselation(em);
227
228         return em;
229 }
230
231 static float vertarray_size(MVert *mvert, int numVerts, int axis)
232 {
233         int i;
234         float min_co, max_co;
235
236         /* if there are no vertices, width is 0 */
237         if(numVerts == 0) return 0;
238
239         /* find the minimum and maximum coordinates on the desired axis */
240         min_co = max_co = mvert->co[axis];
241         ++mvert;
242         for(i = 1; i < numVerts; ++i, ++mvert) {
243                 if(mvert->co[axis] < min_co) min_co = mvert->co[axis];
244                 if(mvert->co[axis] > max_co) max_co = mvert->co[axis];
245         }
246
247         return max_co - min_co;
248 }
249
250 /* finds the best possible flipped name. For renaming; check for unique names afterwards */
251 /* if strip_number: removes number extensions */
252 static void vertgroup_flip_name (char *name, int strip_number)
253 {
254         int     len;
255         char    prefix[128]={""};   /* The part before the facing */
256         char    suffix[128]={""};   /* The part after the facing */
257         char    replace[128]={""};  /* The replacement string */
258         char    number[128]={""};   /* The number extension string */
259         char    *index=NULL;
260
261         len= strlen(name);
262         if(len<3) return; // we don't do names like .R or .L
263
264         /* We first check the case with a .### extension, let's find the last period */
265         if(isdigit(name[len-1])) {
266                 index= strrchr(name, '.'); // last occurrance
267                 if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
268                         if(strip_number==0) 
269                                 strcpy(number, index);
270                         *index= 0;
271                         len= strlen(name);
272                 }
273         }
274
275         strcpy (prefix, name);
276
277 #define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_')
278
279         /* first case; separator . - _ with extensions r R l L  */
280         if( IS_SEPARATOR(name[len-2]) ) {
281                 switch(name[len-1]) {
282                         case 'l':
283                                 prefix[len-1]= 0;
284                                 strcpy(replace, "r");
285                                 break;
286                         case 'r':
287                                 prefix[len-1]= 0;
288                                 strcpy(replace, "l");
289                                 break;
290                         case 'L':
291                                 prefix[len-1]= 0;
292                                 strcpy(replace, "R");
293                                 break;
294                         case 'R':
295                                 prefix[len-1]= 0;
296                                 strcpy(replace, "L");
297                                 break;
298                 }
299         }
300         /* case; beginning with r R l L , with separator after it */
301         else if( IS_SEPARATOR(name[1]) ) {
302                 switch(name[0]) {
303                         case 'l':
304                                 strcpy(replace, "r");
305                                 strcpy(suffix, name+1);
306                                 prefix[0]= 0;
307                                 break;
308                         case 'r':
309                                 strcpy(replace, "l");
310                                 strcpy(suffix, name+1);
311                                 prefix[0]= 0;
312                                 break;
313                         case 'L':
314                                 strcpy(replace, "R");
315                                 strcpy(suffix, name+1);
316                                 prefix[0]= 0;
317                                 break;
318                         case 'R':
319                                 strcpy(replace, "L");
320                                 strcpy(suffix, name+1);
321                                 prefix[0]= 0;
322                                 break;
323                 }
324         }
325         else if(len > 5) {
326                 /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
327                 index = BLI_strcasestr(prefix, "right");
328                 if (index==prefix || index==prefix+len-5) {
329                         if(index[0]=='r') 
330                                 strcpy (replace, "left");
331                         else {
332                                 if(index[1]=='I') 
333                                         strcpy (replace, "LEFT");
334                                 else
335                                         strcpy (replace, "Left");
336                         }
337                         *index= 0;
338                         strcpy (suffix, index+5);
339                 }
340                 else {
341                         index = BLI_strcasestr(prefix, "left");
342                         if (index==prefix || index==prefix+len-4) {
343                                 if(index[0]=='l') 
344                                         strcpy (replace, "right");
345                                 else {
346                                         if(index[1]=='E') 
347                                                 strcpy (replace, "RIGHT");
348                                         else
349                                                 strcpy (replace, "Right");
350                                 }
351                                 *index= 0;
352                                 strcpy (suffix, index+4);
353                         }
354                 }
355         }
356
357 #undef IS_SEPARATOR
358
359         sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
360 }
361
362 typedef struct IndexMapEntry {
363         /* the new vert index that this old vert index maps to */
364         int new;
365         /* -1 if this vert isn't merged, otherwise the old vert index it
366         * should be replaced with
367         */
368         int merge;
369         /* 1 if this vert's first copy is merged with the last copy of its
370         * merge target, otherwise 0
371         */
372         short merge_final;
373 } IndexMapEntry;
374
375 /* indexMap - an array of IndexMap entries
376  * oldIndex - the old index to map
377  * copyNum - the copy number to map to (original = 0, first copy = 1, etc.)
378  */
379 static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum)
380 {
381         if(indexMap[oldIndex].merge < 0) {
382                 /* vert wasn't merged, so use copy of this vert */
383                 return indexMap[oldIndex].new + copyNum;
384         } else if(indexMap[oldIndex].merge == oldIndex) {
385                 /* vert was merged with itself */
386                 return indexMap[oldIndex].new;
387         } else {
388                 /* vert was merged with another vert */
389                 /* follow the chain of merges to the end, or until we've passed
390                 * a number of vertices equal to the copy number
391                 */
392                 if(copyNum <= 0)
393                         return indexMap[oldIndex].new;
394                 else
395                         return calc_mapping(indexMap, indexMap[oldIndex].merge,
396                                             copyNum - 1);
397         }
398 }
399
400 static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
401                                           Scene *scene, Object *ob, DerivedMesh *dm,
402                                           int initFlags)
403 {
404         DerivedMesh *cddm = dm; //copying shouldn't be necassary here, as all modifiers return CDDM's
405         BMEditMesh *em = CDDM_To_BMesh(cddm, NULL);
406         BMOperator op, oldop, weldop;
407         int i, j, indexLen;
408         /* offset matrix */
409         float offset[4][4];
410         float final_offset[4][4];
411         float tmp_mat[4][4];
412         float length = amd->length;
413         int count = amd->count, maxVerts;
414         int finalVerts, finalEdges, finalFaces;
415         int *indexMap = NULL;
416         DerivedMesh *start_cap = NULL, *end_cap = NULL;
417         MVert *src_mvert;
418
419         /* need to avoid infinite recursion here */
420         if(amd->start_cap && amd->start_cap != ob)
421                 start_cap = mesh_get_derived_final(scene, amd->start_cap, CD_MASK_MESH);
422         if(amd->end_cap && amd->end_cap != ob)
423                 end_cap = mesh_get_derived_final(scene, amd->end_cap, CD_MASK_MESH);
424
425         Mat4One(offset);
426
427         src_mvert = cddm->getVertArray(dm);
428         maxVerts = cddm->getNumVerts(dm);
429
430         if(amd->offset_type & MOD_ARR_OFF_CONST)
431                 VecAddf(offset[3], offset[3], amd->offset);
432         if(amd->offset_type & MOD_ARR_OFF_RELATIVE) {
433                 for(j = 0; j < 3; j++)
434                         offset[3][j] += amd->scale[j] * vertarray_size(src_mvert,
435                                         maxVerts, j);
436         }
437
438         if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
439                 float obinv[4][4];
440                 float result_mat[4][4];
441
442                 if(ob)
443                         Mat4Invert(obinv, ob->obmat);
444                 else
445                         Mat4One(obinv);
446
447                 Mat4MulSerie(result_mat, offset,
448                                  obinv, amd->offset_ob->obmat,
449                                  NULL, NULL, NULL, NULL, NULL);
450                 Mat4CpyMat4(offset, result_mat);
451         }
452
453         if(amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
454                 Curve *cu = amd->curve_ob->data;
455                 if(cu) {
456                         float tmp_mat[3][3];
457                         float scale;
458                         
459                         object_to_mat3(amd->curve_ob, tmp_mat);
460                         scale = Mat3ToScalef(tmp_mat);
461                                 
462                         if(!cu->path) {
463                                 cu->flag |= CU_PATH; // needed for path & bevlist
464                                 makeDispListCurveTypes(scene, amd->curve_ob, 0);
465                         }
466                         if(cu->path)
467                                 length = scale*cu->path->totdist;
468                 }
469         }
470
471         /* calculate the maximum number of copies which will fit within the
472         prescribed length */
473         if(amd->fit_type == MOD_ARR_FITLENGTH
474                   || amd->fit_type == MOD_ARR_FITCURVE)
475         {
476                 float dist = sqrt(INPR(offset[3], offset[3]));
477
478                 if(dist > 1e-6f)
479                         /* this gives length = first copy start to last copy end
480                         add a tiny offset for floating point rounding errors */
481                         count = (length + 1e-6f) / dist;
482                 else
483                         /* if the offset has no translation, just make one copy */
484                         count = 1;
485         }
486
487         if(count < 1)
488                 count = 1;
489
490         /* allocate memory for count duplicates (including original) plus
491                   * start and end caps
492         */
493         finalVerts = dm->getNumVerts(dm) * count;
494         finalEdges = dm->getNumEdges(dm) * count;
495         finalFaces = dm->getNumFaces(dm) * count;
496         if(start_cap) {
497                 finalVerts += start_cap->getNumVerts(start_cap);
498                 finalEdges += start_cap->getNumEdges(start_cap);
499                 finalFaces += start_cap->getNumFaces(start_cap);
500         }
501         if(end_cap) {
502                 finalVerts += end_cap->getNumVerts(end_cap);
503                 finalEdges += end_cap->getNumEdges(end_cap);
504                 finalFaces += end_cap->getNumFaces(end_cap);
505         }
506
507         /* calculate the offset matrix of the final copy (for merging) */ 
508         Mat4One(final_offset);
509
510         for(j=0; j < count - 1; j++) {
511                 Mat4MulMat4(tmp_mat, final_offset, offset);
512                 Mat4CpyMat4(final_offset, tmp_mat);
513         }
514
515         BMO_Init_Op(&weldop, "weldverts");
516         BMO_InitOpf(em->bm, &op, "dupe geom=%avef");
517         oldop = op;
518         for (j=0; j < count; j++) {
519                 BMVert *v, *v2;
520                 BMOpSlot *s1;
521                 BMOpSlot *s2;
522
523                 BMO_InitOpf(em->bm, &op, "dupe geom=%s", &oldop, j==0 ? "geom" : "newout");
524                 BMO_Exec_Op(em->bm, &op);
525
526                 s1 = BMO_GetSlot(&op, "geom");
527                 s2 = BMO_GetSlot(&op, "newout");
528
529                 BMO_CallOpf(em->bm, "transform mat=%m4 verts=%s", offset, &op, "newout");
530
531                 #define _E(s, i) ((BMVert**)(s)->data.buf)[i]
532
533                 /*calculate merge mapping*/
534                 if (j == 0) {
535                         BMOperator findop;
536                         BMOIter oiter;
537                         BMVert *v, *v2;
538                         BMHeader *h;
539
540                         BMO_InitOpf(em->bm, &findop, 
541                                 "finddoubles verts=%av dist=%f keepverts=%s", 
542                                 amd->merge_dist, &op, "geom");
543
544                         i = 0;
545                         BMO_ITER(h, &oiter, em->bm, &op, "geom", BM_ALL) {
546                                 BMINDEX_SET(h, i);
547                                 i++;
548                         }
549
550                         BMO_ITER(h, &oiter, em->bm, &op, "newout", BM_ALL) {
551                                 BMINDEX_SET(h, i);
552                                 i++;
553                         }
554
555                         BMO_Exec_Op(em->bm, &findop);
556
557                         indexLen = i;
558                         indexMap = MEM_callocN(sizeof(int)*indexLen, "indexMap");
559
560                         /*element type argument doesn't do anything here*/
561                         BMO_ITER(v, &oiter, em->bm, &findop, "targetmapout", 0) {
562                                 v2 = BMO_IterMapValp(&oiter);
563
564                                 indexMap[BMINDEX_GET(v)] = BMINDEX_GET(v2)+1;
565                         }
566
567                         BMO_Finish_Op(em->bm, &findop);
568                 } 
569
570                 /*generate merge mappping using index map.  we do this by using the
571                   operator slots as lookup arrays.*/
572                 #define E(i) (i) < s1->len ? _E(s1, i) : _E(s2, (i)-s1->len)
573
574                 for (i=0; i<indexLen; i++) {
575                         if (!indexMap[i]) continue;
576
577                         v = E(i);
578                         v2 = E(indexMap[i]-1);
579
580                         BMO_Insert_MapPointer(em->bm, &weldop, "targetmap", v, v2);
581                 }
582
583                 #undef E
584                 #undef _E
585
586                 BMO_Finish_Op(em->bm, &oldop);
587                 oldop = op;
588         }
589
590         if (j > 0) BMO_Finish_Op(em->bm, &op);
591
592         if (amd->flags & MOD_ARR_MERGE)
593                 BMO_Exec_Op(em->bm, &weldop);
594
595         BMO_Finish_Op(em->bm, &weldop);
596
597         BMEdit_RecalcTesselation(em);
598         cddm = CDDM_from_BMEditMesh(em, NULL);
599
600         BMEdit_Free(em);
601         MEM_freeN(indexMap);
602
603         return cddm;
604 }
605
606 DerivedMesh *arrayModifier_applyModifier(ModifierData *md, Object *ob, 
607                                          DerivedMesh *derivedData,
608                                          int useRenderParams, int isFinalCalc)
609 {
610         DerivedMesh *result;
611         ArrayModifierData *amd = (ArrayModifierData*) md;
612
613         result = arrayModifier_doArray(amd, md->scene, ob, derivedData, 0);
614
615         //if(result != derivedData)
616         //      CDDM_calc_normals(result);
617
618         return result;
619 }
620
621 DerivedMesh *arrayModifier_applyModifierEM(ModifierData *md, Object *ob,
622                                            BMEditMesh *editData, 
623                                            DerivedMesh *derivedData)
624 {
625         return arrayModifier_applyModifier(md, ob, derivedData, 0, 1);
626 }
627
628 /* Mirror */
629 #define VERT_NEW        1
630
631 DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
632                 Object *ob,
633                 DerivedMesh *dm,
634                 int initFlags,
635                 int axis)
636 {
637         float tolerance = mmd->tolerance;
638         DerivedMesh *result, *cddm;
639         BMEditMesh *em;
640         BMesh *bm;
641         BMOIter siter1;
642         BMOperator op;
643         BMVert *v1;
644         int vector_size=0, a, b;
645         bDeformGroup *def, *defb;
646         bDeformGroup **vector_def = NULL;
647         float mtx[4][4], imtx[4][4];
648         int j;
649
650         cddm = dm; //copying shouldn't be necassary here, as all modifiers return CDDM's
651         em = CDDM_To_BMesh(dm, NULL);
652
653         /*convienence variable*/
654         bm = em->bm;
655
656         if (mmd->flag & MOD_MIR_VGROUP) {
657                 /* calculate the number of deformedGroups */
658                 for(vector_size = 0, def = ob->defbase.first; def;
659                     def = def->next, vector_size++);
660
661                 /* load the deformedGroups for fast access */
662                 vector_def =
663                     (bDeformGroup **)MEM_mallocN(sizeof(bDeformGroup*) * vector_size,
664                                                  "group_index");
665                 for(a = 0, def = ob->defbase.first; def; def = def->next, a++) {
666                         vector_def[a] = def;
667                 }
668         }
669
670         if (mmd->mirror_ob) {
671                 float mtx2[4][4], vec[3];
672                 
673                 Mat4Invert(mtx2, mmd->mirror_ob->obmat);
674                 Mat4MulMat4(mtx, ob->obmat, mtx2);
675         } else {
676                 Mat4One(mtx);
677         }
678
679         BMO_InitOpf(bm, &op, "mirror geom=%avef mat=%m4 mergedist=%f axis=%d", 
680                     mtx, mmd->tolerance, axis);
681         
682         BMO_Exec_Op(bm, &op);
683
684         BMO_CallOpf(bm, "reversefaces faces=%s", &op, "newout");
685         
686         /*handle vgroup stuff*/
687         if (mmd->flag & MOD_MIR_VGROUP) {
688                 BMO_ITER(v1, &siter1, bm, &op, "newout", BM_VERT) {
689                         MDeformVert *dvert = CustomData_bmesh_get(&bm->vdata, v1->head.data, CD_MDEFORMVERT);
690                         
691                         if (dvert) {
692                                 for(j = 0; j < dvert[0].totweight; ++j) {
693                                         char tmpname[32];
694                                         
695                                         if(dvert->dw[j].def_nr < 0 ||
696                                            dvert->dw[j].def_nr >= vector_size)
697                                                 continue;
698                                         
699                                         def = vector_def[dvert->dw[j].def_nr];
700                                         strcpy(tmpname, def->name);
701                                         vertgroup_flip_name(tmpname,0);
702                                         
703                                         for(b = 0, defb = ob->defbase.first; defb;
704                                             defb = defb->next, b++)
705                                         {
706                                                 if(!strcmp(defb->name, tmpname))
707                                                 {
708                                                         dvert->dw[j].def_nr = b;
709                                                         break;
710                                                 }
711                                         }
712                                 }
713                         }
714                 }
715         }
716         
717         BMO_Finish_Op(bm, &op);
718
719         BMEdit_RecalcTesselation(em);
720         result = CDDM_from_BMEditMesh(em, NULL); //CDDM_copy(getEditDerivedBMesh(em, ob, NULL), 0);
721
722         BMEdit_Free(em);
723         MEM_freeN(em);
724
725         if (vector_def) MEM_freeN(vector_def);
726
727         return result;
728 }