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