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