forgot that you can't simply grow an array by one, when your rotating your indexes.
[blender.git] / source / blender / bmesh / operators / subdivideop.c
1 #include "MEM_guardedalloc.h"
2
3 #include "BKE_utildefines.h"
4
5 #include "BLI_arithb.h"
6 #include "BLI_rand.h"
7
8 #include "DNA_object_types.h"
9
10 #include "ED_mesh.h"
11
12 #include "bmesh.h"
13 #include "mesh_intern.h"
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19
20 #define SUBD_SPLIT      1
21 #define FACE_NEW        1
22 #define MAX_FACE        800
23
24 /*stuff for the flag paramter.  note that
25   what used to live in "beauty" and
26   in "seltype" live here.  still have to
27   convert the beauty flags over, which
28   is why it starts at 128 (to avoid
29   collision).*/
30 #define SELTYPE_INNER   128
31
32
33 /*
34 NOTE: beauty has been renamed to flag!
35 */
36
37 /*
38 note: this is a pattern-based edge subdivider.
39 it tries to match a pattern to edge selections on faces,
40 then executes functions to cut them.
41 */
42 typedef struct subdpattern {
43         int seledges[20]; //selected edges mask, for splitting
44
45         /*verts starts at the first new vert cut, not the first vert in the
46           face*/
47         void (*connectexec)(BMesh *bm, BMFace *face, BMVert **verts, 
48                             int numcuts, int flag, float rad);
49         int len; /*total number of verts*/
50 } subdpattern;
51
52 /*generic subdivision rules:
53   
54   * two selected edges in a face should make a link
55     between them.
56
57   * one edge should do, what? make pretty topology, or just
58     split the edge only?
59 */
60
61 /* calculates offset for co, based on fractal, sphere or smooth settings  */
62 static void alter_co(float *co, BMEdge *edge, float rad, int flag, float perc,
63                      BMVert *vsta, BMVert *vend)
64 {
65         float vec1[3], fac;
66         
67         if(flag & B_SMOOTH) {
68                 /* we calculate an offset vector vec1[], to be added to *co */
69                 float len, fac, nor[3], nor1[3], nor2[3];
70                 
71                 VecSubf(nor, vsta->co, vend->co);
72                 len= 0.5f*Normalize(nor);
73         
74                 VECCOPY(nor1, vsta->no);
75                 VECCOPY(nor2, vend->no);
76         
77                 /* cosine angle */
78                 fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
79                 
80                 vec1[0]= fac*nor1[0];
81                 vec1[1]= fac*nor1[1];
82                 vec1[2]= fac*nor1[2];
83         
84                 /* cosine angle */
85                 fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
86                 
87                 vec1[0]+= fac*nor2[0];
88                 vec1[1]+= fac*nor2[1];
89                 vec1[2]+= fac*nor2[2];
90                 
91                 vec1[0]*= rad*len;
92                 vec1[1]*= rad*len;
93                 vec1[2]*= rad*len;
94                 
95                 co[0] += vec1[0];
96                 co[1] += vec1[1];
97                 co[2] += vec1[2];
98         }
99         else {
100                 if(rad > 0.0) {   /* subdivide sphere */
101                         Normalize(co);
102                         co[0]*= rad;
103                         co[1]*= rad;
104                         co[2]*= rad;
105                 }
106                 else if(rad< 0.0) {  /* fractal subdivide */
107                         fac= rad* VecLenf(vsta->co, vend->co);
108                         vec1[0]= fac*(float)(0.5-BLI_drand());
109                         vec1[1]= fac*(float)(0.5-BLI_drand());
110                         vec1[2]= fac*(float)(0.5-BLI_drand());
111                         VecAddf(co, co, vec1);
112                 }
113
114         }
115 }
116
117 /* assumes in the edge is the correct interpolated vertices already */
118 /* percent defines the interpolation, rad and flag are for special options */
119 /* results in new vertex with correct coordinate, vertex normal and weight group info */
120 static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, float rad, 
121                                          int flag, float percent, BMEdge **out,
122                                          BMVert *vsta, BMVert *vend)
123 {
124         BMVert *ev;
125 //      float co[3];
126         
127         ev = BM_Split_Edge(bm, edge->v1, edge, out, percent, 1);
128         if (flag & SELTYPE_INNER) BM_Select_Vert(bm, ev, 1);
129
130         /* offset for smooth or sphere or fractal */
131         alter_co(ev->co, edge, rad, flag, percent, vsta, vend);
132
133 #if 0 //TODO
134         /* clip if needed by mirror modifier */
135         if (edge->v1->f2) {
136                 if ( edge->v1->f2 & edge->v2->f2 & 1) {
137                         co[0]= 0.0f;
138                 }
139                 if ( edge->v1->f2 & edge->v2->f2 & 2) {
140                         co[1]= 0.0f;
141                 }
142                 if ( edge->v1->f2 & edge->v2->f2 & 4) {
143                         co[2]= 0.0f;
144                 }
145         }
146 #endif  
147         
148         return ev;
149 }
150
151 static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge, 
152                                 int curpoint, int totpoint, float rad, 
153                                 int flag, BMEdge **newe,
154                                 BMVert *vsta, BMVert *vend)
155 {
156         BMVert *ev;
157         float percent;
158          
159         if (flag & (B_PERCENTSUBD) && totpoint == 1)
160                 /*I guess the idea is vertices store what
161                   percent to use?*/
162                 //percent=(float)(edge->tmp.l)/32768.0f;
163                 percent= 1.0; //edge->tmp.fp;
164         else {
165                 percent= 1.0f/(float)(totpoint+1-curpoint);
166
167         }
168         
169         /*{
170                 float co[3], co2[3];
171                 VecSubf(co, edge->v2->co, edge->v1->co);
172                 VecMulf(co, 1.0f/(float)(totpoint+1-curpoint));
173                 VecAddf(co2, edge->v1->co, co);
174 */
175                 ev= bm_subdivide_edge_addvert(bm, edge, rad, flag, percent, 
176                                        newe, vsta, vend);
177                 
178 /*              VECCOPY(ev->co, co2);
179         }
180 */      
181         return ev;
182 }
183
184 static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, float rad,
185                                   int flag, int numcuts, 
186                                   BMVert *vsta, BMVert *vend) {
187         BMEdge *eed = edge, *newe;
188         BMVert *v;
189         int i;
190
191         for(i=0;i<numcuts;i++) {
192                 v = subdivideedgenum(bm, eed, i, numcuts, rad, 
193                         flag, &newe, vsta, vend);
194                 BMO_SetFlag(bm, v, SUBD_SPLIT);
195                 BMO_SetFlag(bm, eed, SUBD_SPLIT);
196         }
197 }
198
199 /*note: the patterns are rotated as necassary to
200   match the input geometry.  they're based on the
201   pre-split state of the  face*/
202
203 /*
204      
205 v3---------v2
206 |          |
207 |          |
208 |          |
209 |          |
210 v4---v0---v1
211
212 */
213 static void q_1edge_split(BMesh *bm, BMFace *face, BMVert **vlist, int numcuts,
214                           int flag, float rad) {
215         BMFace *nf;
216         int i, add;
217
218         /*if it's odd, the middle face is a quad, otherwise it's a triangle*/
219         if (numcuts % 2==0) {
220                 add = 2;
221                 for (i=0; i<numcuts; i++) {
222                         if (i == numcuts/2) add -= 1;
223                         BM_Connect_Verts(bm, vlist[i], vlist[numcuts+add], 
224                                            &nf);
225                 }
226         } else {
227                 add = 2;
228                 for (i=0; i<numcuts; i++) {
229                         BM_Connect_Verts(bm, vlist[i], vlist[numcuts+add], 
230                                            &nf);
231                         if (i == numcuts/2) {
232                                 add -= 1;
233                                 BM_Connect_Verts(bm, vlist[i], 
234                                                    vlist[numcuts+add],
235                                                    &nf);
236                         }
237                 }
238
239         }
240 }
241
242 subdpattern q_1edge = {
243         {1, 0, 0, 0},
244         q_1edge_split,
245         4,
246 };
247
248
249 /*
250  
251 v4---v3---v2
252 |     s    |
253 |          |
254 |          |
255 |     s    |
256 v5---v0---v1
257
258 */
259 static void q_2edge_op_split(BMesh *bm, BMFace *face, BMVert **vlist, 
260                              int numcuts, int flag, float rad) {
261         BMFace *nf;
262         int i;
263         
264         for (i=0; i<numcuts; i++) {
265                 BM_Connect_Verts(bm, vlist[i],vlist[(numcuts-i-1)+numcuts+2],
266                                    &nf);
267         }
268 }
269
270 subdpattern q_2edge_op = {
271         {1, 0, 1, 0},
272         q_2edge_op_split,
273         4,
274 };
275
276 /*
277 v6--------v5
278 |          |
279 |          |v4s
280 |          |v3s
281 |   s  s   |
282 v7-v0--v1-v2
283
284 */
285 static void q_2edge_split(BMesh *bm, BMFace *face, BMVert **vlist, 
286                              int numcuts, int flag, float rad) {
287         BMFace *nf;
288         int i;
289         
290         for (i=0; i<numcuts; i++) {
291                 BM_Connect_Verts(bm, vlist[i], vlist[numcuts+(numcuts-i)],
292                                    &nf);
293         }
294         BM_Connect_Verts(bm, vlist[numcuts*2+3], vlist[numcuts*2+1], &nf);
295 }
296
297 subdpattern q_2edge = {
298         {1, 1, 0, 0},
299         q_2edge_split,
300         4,
301 };
302
303 /*  s   s
304 v8--v7--v6-v5
305 |          |
306 |          v4 s
307 |          |
308 |          v3 s
309 |   s  s   |
310 v9-v0--v1-v2
311
312 */
313 static void q_3edge_split(BMesh *bm, BMFace *face, BMVert **vlist, 
314                              int numcuts, int flag, float rad) {
315         BMFace *nf;
316         int i, add=0;
317         
318         for (i=0; i<numcuts; i++) {
319                 if (i == numcuts/2) {
320                         if (numcuts % 2 != 0) {
321                                 BM_Connect_Verts(bm, vlist[numcuts-i-1+add], 
322                                                  vlist[i+numcuts+1], &nf);
323                         }
324                         add = numcuts*2+2;
325                 }
326                 BM_Connect_Verts(bm, vlist[numcuts-i-1+add], 
327                                      vlist[i+numcuts+1], &nf);
328         }
329
330         for (i=0; i<numcuts/2+1; i++) {
331                 BM_Connect_Verts(bm, vlist[i],vlist[(numcuts-i)+numcuts*2+1],
332                                    &nf);
333         }
334 }
335
336 subdpattern q_3edge = {
337         {1, 1, 1, 0},
338         q_3edge_split,
339         4,
340 };
341
342 /*
343  
344            v8--v7-v6--v5
345            |     s    |
346            |v9 s     s|v4
347 first line |          |   last line
348            |v10s s   s|v3
349            v11-v0--v1-v2
350
351            it goes from bottom up
352 */
353 static void q_4edge_split(BMesh *bm, BMFace *face, BMVert **vlist, int numcuts,
354                           int flag, float rad) {
355         BMFace *nf;
356         BMVert *v, *v1, *v2;
357         BMEdge *e, *ne;
358         BMVert **lines = MEM_callocN(sizeof(BMVert*)*(numcuts+2)*(numcuts+2),
359                                      "q_4edge_split");
360         int i, j, a, b, s=numcuts+2, totv=numcuts*4+4;
361
362         /*build a 2-dimensional array of verts,
363           containing every vert (and all new ones)
364           in the face.*/
365
366         /*first line*/
367         for (i=0; i<numcuts+2; i++) {
368                 lines[i] = vlist[numcuts*3+2+(numcuts-i+1)];
369         }
370
371         /*last line*/
372         for (i=0; i<numcuts+2; i++) {
373                 lines[(s-1)*s+i] = vlist[numcuts+i];
374         }
375         
376         /*first and last members of middle lines*/
377         for (i=0; i<numcuts; i++) {
378                 a = i;
379                 b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1);
380                 
381                 e = BM_Connect_Verts(bm, vlist[a], vlist[b], &nf);
382                 if (flag & SELTYPE_INNER) {
383                         BM_Select_Edge(bm, e, 1);
384                         BM_Select_Face(bm, nf, 1);
385                 }
386                 
387                 v1 = lines[(i+1)*s] = vlist[a];
388                 v2 = lines[(i+1)*s + s-1] = vlist[b];
389
390                 for (a=0; a<numcuts; a++) {
391                         v = subdivideedgenum(bm, e, a, numcuts, rad, flag, &ne,
392                                              v1, v2);
393                         if (flag & SELTYPE_INNER) {
394                                 BM_Select_Edge(bm, ne, 1);
395                         }
396                         lines[(i+1)*s+a+1] = v;
397                 }
398         }
399
400         for (i=1; i<numcuts+2; i++) {
401                 for (j=1; j<numcuts+1; j++) {
402                         a = i*s + j;
403                         b = (i-1)*s + j;
404                         e = BM_Connect_Verts(bm, lines[a], lines[b], &nf);
405                         if (flag & SELTYPE_INNER) {
406                                 BM_Select_Edge(bm, e, 1);
407                                 BM_Select_Face(bm, nf, 1);
408                         }
409                 }
410         }
411
412         MEM_freeN(lines);
413 }
414
415 /*    v3
416      / \
417     /   \
418    /     \
419   /       \
420  /         \
421 v4--v0--v1--v2
422     s    s
423 */
424 static void t_1edge_split(BMesh *bm, BMFace *face, BMVert **vlist, 
425                              int numcuts, int flag, float rad) {
426         BMFace *nf;
427         int i;
428         
429         for (i=0; i<numcuts; i++) {
430                 BM_Connect_Verts(bm, vlist[i], vlist[numcuts+1], &nf);
431         }
432 }
433
434 subdpattern t_1edge = {
435         {1, 0, 0},
436         t_1edge_split,
437         3,
438 };
439
440 /*    v5
441      / \
442     /   \ v4 s
443    /     \
444   /       \ v3 s
445  /         \
446 v6--v0--v1--v2
447     s   s
448 */
449 static void t_2edge_split(BMesh *bm, BMFace *face, BMVert **vlist, 
450                              int numcuts, int flag, float rad) {
451         BMFace *nf;
452         int i;
453         
454         for (i=0; i<numcuts; i++) {
455                 BM_Connect_Verts(bm, vlist[i], vlist[numcuts+numcuts-i], &nf);
456         }
457 }
458
459 subdpattern t_2edge = {
460         {1, 1, 0},
461         t_2edge_split,
462         3,
463 };
464
465
466 /*     v5
467       / \
468  s v6/---\ v4 s
469     / \ / \
470 sv7/---v---\ v3 s
471   /  \/  \/ \
472  v8--v0--v1--v2
473     s    s
474 */
475 static void t_3edge_split(BMesh *bm, BMFace *face, BMVert **vlist, 
476                              int numcuts, int flag, float rad) {
477         BMFace *nf;
478         BMEdge *e, *ne;
479         BMVert ***lines, *v;
480         void *stackarr[1];
481         int i, j, a, b;
482         
483         /*number of verts in each line*/
484         lines = MEM_callocN(sizeof(void*)*(numcuts+2), "triangle vert table");
485         
486         lines[0] = (BMVert**) stackarr;
487         lines[0][0] = vlist[numcuts*2+1];
488         
489         lines[1+numcuts] = MEM_callocN(sizeof(void*)*(numcuts+2), 
490                                        "triangle vert table 2");
491         for (i=0; i<numcuts; i++) {
492                 lines[1+numcuts][1+i] = vlist[i];
493         }
494         lines[1+numcuts][0] = vlist[numcuts*3+2];
495         lines[1+numcuts][1+numcuts] = vlist[numcuts];
496
497         for (i=0; i<numcuts; i++) {
498                 lines[i+1] = MEM_callocN(sizeof(void*)*(2+i), 
499                                        "triangle vert table row");
500                 a = numcuts*2 + 2 + i;
501                 b = numcuts + numcuts - i;
502                 e = BM_Connect_Verts(bm, vlist[a], vlist[b], &nf);
503                 
504                 if (flag & SELTYPE_INNER) {
505                         BM_Select_Edge(bm, e, 1);
506                         BM_Select_Face(bm, nf, 1);
507                 }
508
509                 lines[i+1][0] = vlist[a];
510                 lines[i+1][1+i] = vlist[b];
511
512                 for (j=0; j<i; j++) {
513                         v = subdivideedgenum(bm, e, j, i, rad, flag, &ne,
514                                              vlist[a], vlist[b]);
515                         lines[i+1][j+1] = v;
516
517                         if (flag & SELTYPE_INNER) {
518                                 BM_Select_Edge(bm, ne, 1);
519                         }
520                 }
521         }
522         
523
524 /*     v5
525       / \
526  s v6/---\ v4 s
527     / \ / \
528 sv7/---v---\ v3 s
529   /  \/  \/ \
530  v8--v0--v1--v2
531     s    s
532 */
533         for (i=1; i<numcuts+1; i++) {
534                 for (j=0; j<i; j++) {
535                         e= BM_Connect_Verts(bm, lines[i][j], lines[i+1][j+1],
536                                            &nf);
537                         if (flag & SELTYPE_INNER) {
538                                 BM_Select_Edge(bm, e, 1);
539                                 BM_Select_Face(bm, nf, 1);
540                         }
541
542                         e= BM_Connect_Verts(bm,lines[i][j+1],lines[i+1][j+1],
543                                            &nf);
544                         if (flag & SELTYPE_INNER) {
545                                 BM_Select_Edge(bm, e, 1);
546                                 BM_Select_Face(bm, nf, 1);
547                         }
548                 }
549         }
550
551         for (i=1; i<numcuts+2; i++) {
552                 MEM_freeN(lines[i]);
553         }
554
555         MEM_freeN(lines);
556 }
557
558 subdpattern t_3edge = {
559         {1, 1, 1},
560         t_3edge_split,
561         3,
562 };
563
564
565 subdpattern q_4edge = {
566         {1, 1, 1, 1},
567         q_4edge_split,
568         4,
569 };
570
571 subdpattern *patterns[] = {
572         &q_1edge,
573         &q_2edge_op,
574         &q_4edge,
575         &q_3edge,
576         &q_2edge,
577         &t_1edge,
578         &t_2edge,
579         &t_3edge,
580 };
581
582 #define PLEN    (sizeof(patterns) / sizeof(void*))
583
584 typedef struct subd_facedata {
585         BMVert *start; subdpattern *pat;
586 } subd_facedata;
587
588 void esubdivide_exec(BMesh *bmesh, BMOperator *op)
589 {
590         BMOpSlot *einput;
591         BMEdge *edge, **edges = NULL;
592         V_DECLARE(edges);
593         BMFace *face;
594         BMLoop *nl;
595         BMVert **verts = NULL;
596         V_DECLARE(verts);
597         BMIter fiter, liter;
598         subdpattern *pat;
599         float rad;
600         int i, j, matched, a, b, numcuts, flag, selaction;
601         subd_facedata *facedata = NULL;
602         V_DECLARE(facedata);
603         
604         BMO_Flag_Buffer(bmesh, op, BMOP_ESUBDIVIDE_EDGES, SUBD_SPLIT);
605         
606         numcuts = BMO_GetSlot(op, BMOP_ESUBDIVIDE_NUMCUTS)->data.i;
607         flag = BMO_GetSlot(op, BMOP_ESUBDIVIDE_FLAG)->data.i;
608         rad = BMO_GetSlot(op, BMOP_ESUBDIVIDE_RADIUS)->data.f;
609
610         selaction = BMO_GetSlot(op, BMOP_ESUBDIVIDE_SELACTION)->data.i;
611         if (selaction == SUBDIV_SELECT_INNER) flag |= SELTYPE_INNER;
612
613         einput = BMO_GetSlot(op, BMOP_ESUBDIVIDE_EDGES);
614         
615         /*first go through and split edges*/
616         for (i=0; i<einput->len; i++) {
617                 edge = ((BMEdge**)einput->data.p)[i];
618                 BMO_SetFlag(bmesh, edge, SUBD_SPLIT);
619         }
620         
621         for (face=BMIter_New(&fiter, bmesh, BM_FACES, NULL);
622              face; face=BMIter_Step(&fiter)) {
623                 /*figure out which pattern to use*/
624                 i = 0;
625                 V_RESET(edges);
626                 V_RESET(verts);
627                 for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
628                      nl; nl=BMIter_Step(&liter)) {
629                         V_GROW(edges);
630                         V_GROW(verts);
631                         edges[i] = nl->e;
632                         verts[i] = nl->v;
633                         i++;
634                 }
635
636                 for (i=0; i<PLEN; i++) {
637                         pat = patterns[i];
638                         if (pat->len == face->len) {
639                                 for (a=0; a<pat->len; a++) {
640                                 matched = 1;
641                                 for (b=0; b<pat->len; b++) {
642                                         j = (b + a) % pat->len;
643                                         if ((!!BMO_TestFlag(bmesh, edges[j], SUBD_SPLIT))
644                                                 != (!!pat->seledges[b])) {
645                                                         matched = 0;
646                                                         break;
647                                         }
648                                 }
649                                 if (matched) break;
650                                 }
651                                 if (matched) {
652                                         V_GROW(facedata);
653                                         BMO_SetFlag(bmesh, face, SUBD_SPLIT);
654                                         j = V_COUNT(facedata) - 1;
655                                         facedata[j].pat = pat;
656                                         facedata[j].start = verts[a];
657                                         break;
658                                 }
659                         }
660                 }
661         }
662
663         /*go through and split edges*/
664         for (i=0; i<einput->len; i++) {
665                 edge = ((BMEdge**)einput->data.p)[i];
666                 bm_subdivide_multicut(bmesh, edge, rad, flag, numcuts,
667                                       edge->v1, edge->v2);
668                 //BM_Split_Edge_Multi(bmesh, edge, numcuts);
669         }
670
671         //if (facedata) V_FREE(facedata);
672         //return;
673
674         i = 0;
675         for (face=BMIter_New(&fiter, bmesh, BM_FACES, NULL);
676              face; face=BMIter_Step(&fiter)) {
677                 /*figure out which pattern to use*/
678                 V_RESET(verts);
679                 if (BMO_TestFlag(bmesh, face, SUBD_SPLIT) == 0) continue;
680                 
681                 pat = facedata[i].pat;
682                 if (!pat) continue;
683
684                 j = a = 0;
685                 for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
686                      nl; nl=BMIter_Step(&liter)) {
687                         if (nl->v == facedata[i].start) {
688                                 a = j+1;
689                                 break;
690                         }
691                         j++;
692                 }
693
694                 for (j=0; j<face->len; j++) {
695                         V_GROW(verts);
696                 }
697                 
698                 j = 0;
699                 for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
700                      nl; nl=BMIter_Step(&liter)) {
701                         b = (j-a+face->len) % face->len;
702                         verts[b] = nl->v;
703                         j += 1;
704                 }
705                 
706                 pat->connectexec(bmesh, face, verts, numcuts, flag, rad);
707                 i++;
708         }
709
710         if (facedata) V_FREE(facedata);
711         if (edges) V_FREE(edges);
712         if (verts) V_FREE(verts);
713 }
714
715 /*editmesh-emulating function*/
716 void BM_esubdivideflag(Object *obedit, BMesh *bm, int selflag, float rad, 
717                        int flag, int numcuts, int seltype) {
718         BMOperator op;
719
720         BMO_Init_Op(&op, BMOP_ESUBDIVIDE);
721         
722         BMO_Set_Int(&op, BMOP_ESUBDIVIDE_NUMCUTS, numcuts);
723         BMO_Set_Int(&op, BMOP_ESUBDIVIDE_FLAG, flag);
724         BMO_Set_Float(&op, BMOP_ESUBDIVIDE_RADIUS, rad);
725         BMO_Set_Int(&op, BMOP_ESUBDIVIDE_SELACTION, seltype);
726         BMO_HeaderFlag_To_Slot(bm, &op, BMOP_ESUBDIVIDE_EDGES, selflag, BM_EDGE);
727         
728         BMO_Exec_Op(bm, &op);
729         BMO_Finish_Op(bm, &op);
730 }
731
732 void BM_esubdivideflag_conv(Object *obedit,EditMesh *em,int selflag, float rad, 
733                        int flag, int numcuts, int seltype) {
734         BMesh *bm = editmesh_to_bmesh(em);
735         EditMesh *em2;
736
737         BM_esubdivideflag(obedit, bm, selflag, rad, flag, numcuts, seltype);
738         em2 = bmesh_to_editmesh(bm);
739         
740         free_editMesh(em);
741         *em = *em2;
742         MEM_freeN(em2);
743         BM_Free_Mesh(bm);
744 }