Style Cleanup: whitespace and some formatting.
[blender.git] / source / blender / bmesh / operators / bmesh_dupeops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Eagar.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include "MEM_guardedalloc.h"
24
25 #include "BLI_utildefines.h"
26
27 #include "BLI_ghash.h"
28 #include "BLI_memarena.h"
29 #include "BLI_array.h"
30 #include "BLI_math.h"
31
32 #include "bmesh.h"
33 #include "bmesh_operators_private.h"
34
35 /* local flag define */
36 #define DUPE_INPUT              1 /* input from operato */
37 #define DUPE_NEW                2
38 #define DUPE_DONE               4
39 #define DUPE_MAPPED             8
40
41 /*
42  *  COPY VERTEX
43  *
44  *   Copy an existing vertex from one bmesh to another.
45  *
46  */
47 static BMVert *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *target_mesh, GHash *vhash)
48 {
49         BMVert *target_vertex = NULL;
50
51         /* Create a new verte */
52         target_vertex = BM_Make_Vert(target_mesh, source_vertex->co,  NULL);
53         
54         /* Insert new vertex into the vert has */
55         BLI_ghash_insert(vhash, source_vertex, target_vertex);
56         
57         /* Copy attribute */
58         BM_Copy_Attributes(source_mesh, target_mesh, source_vertex, target_vertex);
59         
60         /* Set internal op flag */
61         BMO_SetFlag(target_mesh, (BMHeader *)target_vertex, DUPE_NEW);
62         
63         return target_vertex;
64 }
65
66 /*
67  * COPY EDGE
68  *
69  * Copy an existing edge from one bmesh to another.
70  *
71  */
72 static BMEdge *copy_edge(BMOperator *op, BMesh *source_mesh,
73                          BMEdge *source_edge, BMesh *target_mesh,
74                          GHash *vhash, GHash *ehash)
75 {
76         BMEdge *target_edge = NULL;
77         BMVert *target_vert1, *target_vert2;
78         BMFace *face;
79         BMIter fiter;
80         int rlen;
81
82         /* see if any of the neighboring faces are
83          * not being duplicated.  in that case,
84          * add it to the new/old map. */
85         rlen = 0;
86         for (face = BMIter_New(&fiter, source_mesh, BM_FACES_OF_EDGE, source_edge);
87                 face; face = BMIter_Step(&fiter)) {
88                 if (BMO_TestFlag(source_mesh, face, DUPE_INPUT)) {
89                         rlen++;
90                 }
91         }
92
93         /* Lookup v1 and v2 */
94         target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
95         target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
96         
97         /* Create a new edg */
98         target_edge = BM_Make_Edge(target_mesh, target_vert1, target_vert2, NULL, 0);
99         
100         /* add to new/old edge map if necassar */
101         if (rlen < 2) {
102                 /* not sure what non-manifold cases of greater then three
103                  * radial should do. */
104                 BMO_Insert_MapPointer(source_mesh, op, "boundarymap",
105                                       source_edge, target_edge);
106         }
107
108         /* Insert new edge into the edge hash */
109         BLI_ghash_insert(ehash, source_edge, target_edge);
110         
111         /* Copy attributes */
112         BM_Copy_Attributes(source_mesh, target_mesh, source_edge, target_edge);
113         
114         /* Set internal op flags */
115         BMO_SetFlag(target_mesh, (BMHeader *)target_edge, DUPE_NEW);
116         
117         return target_edge;
118 }
119
120 /*
121  * COPY FACE
122  *
123  *  Copy an existing face from one bmesh to another.
124  */
125
126 static BMFace *copy_face(BMOperator *op, BMesh *source_mesh,
127                          BMFace *source_face, BMesh *target_mesh,
128                          BMVert **vtar, BMEdge **edar, GHash *vhash, GHash *ehash)
129 {
130         /* BMVert *target_vert1, *target_vert2; */ /* UNUSED */
131         BMLoop *source_loop, *target_loop;
132         BMFace *target_face = NULL;
133         BMIter iter, iter2;
134         int i;
135         
136         /* lookup the first and second vert */
137 #if 0 /* UNUSED */
138         target_vert1 = BLI_ghash_lookup(vhash, BMIter_New(&iter, source_mesh, BM_VERTS_OF_FACE, source_face));
139         target_vert2 = BLI_ghash_lookup(vhash, BMIter_Step(&iter));
140 #else
141         BMIter_New(&iter, source_mesh, BM_VERTS_OF_FACE, source_face);
142         BMIter_Step(&iter);
143 #endif
144
145         /* lookup edge */
146         for (i = 0, source_loop = BMIter_New(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face);
147              source_loop;
148              source_loop = BMIter_Step(&iter), i++)
149         {
150                 vtar[i] = BLI_ghash_lookup(vhash, source_loop->v);
151                 edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
152         }
153         
154         /* create new fac */
155         target_face = BM_Make_Face(target_mesh, vtar, edar, source_face->len, 0);
156         BMO_Insert_MapPointer(source_mesh, op,
157                               "facemap", source_face, target_face);
158         BMO_Insert_MapPointer(source_mesh, op,
159                               "facemap", target_face, source_face);
160
161         BM_Copy_Attributes(source_mesh, target_mesh, source_face, target_face);
162
163         /* mark the face for outpu */
164         BMO_SetFlag(target_mesh, (BMHeader *)target_face, DUPE_NEW);
165         
166         /* copy per-loop custom dat */
167         BM_ITER(source_loop, &iter, source_mesh, BM_LOOPS_OF_FACE, source_face) {
168                 BM_ITER(target_loop, &iter2, target_mesh, BM_LOOPS_OF_FACE, target_face) {
169                         if (BLI_ghash_lookup(vhash, source_loop->v) == target_loop->v) {
170                                 BM_Copy_Attributes(source_mesh, target_mesh, source_loop, target_loop);
171                                 break;
172                         }
173                 }
174         }
175
176         return target_face;
177 }
178
179 /*
180  * COPY MESH
181  *
182  * Internal Copy function.
183  */
184 static void copy_mesh(BMOperator *op, BMesh *source, BMesh *target)
185 {
186
187         BMVert *v = NULL, *v2;
188         BMEdge *e = NULL;
189         BMFace *f = NULL;
190
191         BLI_array_declare(vtar);
192         BLI_array_declare(edar);
193         BMVert **vtar = NULL;
194         BMEdge **edar = NULL;
195         
196         BMIter verts;
197         BMIter edges;
198         BMIter faces;
199         
200         GHash *vhash;
201         GHash *ehash;
202
203         /* initialize pointer hashe */
204         vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh dupeops v");
205         ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh dupeops e");
206         
207         for (v = BMIter_New(&verts, source, BM_VERTS_OF_MESH, source); v; v = BMIter_Step(&verts)) {
208                 if (BMO_TestFlag(source, (BMHeader *)v, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader *)v, DUPE_DONE))) {
209                         BMIter iter;
210                         int iso = 1;
211
212                         v2 = copy_vertex(source, v, target, vhash);
213
214                         BM_ITER(f, &iter, source, BM_FACES_OF_VERT, v) {
215                                 if (BMO_TestFlag(source, f, DUPE_INPUT)) {
216                                         iso = 0;
217                                         break;
218                                 }
219                         }
220
221                         if (iso) {
222                                 BM_ITER(e, &iter, source, BM_EDGES_OF_VERT, v) {
223                                         if (BMO_TestFlag(source, e, DUPE_INPUT)) {
224                                                 iso = 0;
225                                                 break;
226                                         }
227                                 }
228                         }
229
230                         if (iso) {
231                                 BMO_Insert_MapPointer(source, op, "isovertmap", v, v2);
232                         }
233
234                         BMO_SetFlag(source, (BMHeader *)v, DUPE_DONE);
235                 }
236         }
237
238         /* now we dupe all the edge */
239         for (e = BMIter_New(&edges, source, BM_EDGES_OF_MESH, source); e; e = BMIter_Step(&edges)) {
240                 if (BMO_TestFlag(source, (BMHeader *)e, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader *)e, DUPE_DONE))) {
241                         /* make sure that verts are copie */
242                         if (!BMO_TestFlag(source, (BMHeader *)e->v1, DUPE_DONE)) {
243                                 copy_vertex(source, e->v1, target, vhash);
244                                 BMO_SetFlag(source, (BMHeader *)e->v1, DUPE_DONE);
245                         }
246                         if (!BMO_TestFlag(source, (BMHeader *)e->v2, DUPE_DONE)) {
247                                 copy_vertex(source, e->v2, target, vhash);
248                                 BMO_SetFlag(source, (BMHeader *)e->v2, DUPE_DONE);
249                         }
250                         /* now copy the actual edg */
251                         copy_edge(op, source, e, target,  vhash,  ehash);
252                         BMO_SetFlag(source, (BMHeader *)e, DUPE_DONE);
253                 }
254         }
255
256         /* first we dupe all flagged faces and their elements from sourc */
257         for (f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f = BMIter_Step(&faces)) {
258                 if (BMO_TestFlag(source, (BMHeader *)f, DUPE_INPUT)) {
259                         /* vertex pas */
260                         for (v = BMIter_New(&verts, source, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts)) {
261                                 if (!BMO_TestFlag(source, (BMHeader *)v, DUPE_DONE)) {
262                                         copy_vertex(source, v, target, vhash);
263                                         BMO_SetFlag(source, (BMHeader *)v, DUPE_DONE);
264                                 }
265                         }
266
267                         /* edge pas */
268                         for (e = BMIter_New(&edges, source, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges)) {
269                                 if (!BMO_TestFlag(source, (BMHeader *)e, DUPE_DONE)) {
270                                         copy_edge(op, source, e, target,  vhash,  ehash);
271                                         BMO_SetFlag(source, (BMHeader *)e, DUPE_DONE);
272                                 }
273                         }
274
275                         /* ensure arrays are the right size */
276                         BLI_array_empty(vtar);
277                         BLI_array_empty(edar);
278
279                         BLI_array_growitems(vtar, f->len);
280                         BLI_array_growitems(edar, f->len);
281
282                         copy_face(op, source, f, target, vtar, edar, vhash, ehash);
283                         BMO_SetFlag(source, (BMHeader *)f, DUPE_DONE);
284                 }
285         }
286         
287         /* free pointer hashe */
288         BLI_ghash_free(vhash, NULL, NULL);
289         BLI_ghash_free(ehash, NULL, NULL);
290
291         BLI_array_free(vtar); /* free vert pointer array */
292         BLI_array_free(edar); /* free edge pointer array */
293 }
294
295 /*
296  * Duplicate Operator
297  *
298  * Duplicates verts, edges and faces of a mesh.
299  *
300  * INPUT SLOTS:
301  *
302  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated
303  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated
304  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated
305  *
306  * OUTPUT SLOTS:
307  *
308  * BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices
309  * BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges
310  * BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces
311  * BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices
312  * BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges
313  * BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces
314  *
315  */
316
317 void dupeop_exec(BMesh *bm, BMOperator *op)
318 {
319         BMOperator *dupeop = op;
320         BMesh *bm2 = BMO_Get_Pnt(op, "dest");
321         
322         if (!bm2)
323                 bm2 = bm;
324                 
325         /* flag inpu */
326         BMO_Flag_Buffer(bm, dupeop, "geom", DUPE_INPUT, BM_ALL);
327
328         /* use the internal copy functio */
329         copy_mesh(dupeop, bm, bm2);
330         
331         /* Outpu */
332         /* First copy the input buffers to output buffers - original dat */
333         BMO_CopySlot(dupeop, dupeop, "geom", "origout");
334
335         /* Now alloc the new output buffer */
336         BMO_Flag_To_Slot(bm, dupeop, "newout", DUPE_NEW, BM_ALL);
337 }
338
339 /* executes the duplicate operation, feeding elements of
340  * type flag etypeflag and header flag flag to it.  note,
341  * to get more useful information (such as the mapping from
342  * original to new elements) you should run the dupe op manually */
343 void BMOP_DupeFromFlag(BMesh *bm, int etypeflag, const char hflag)
344 {
345         BMOperator dupeop;
346
347         BMO_Init_Op(bm, &dupeop, "dupe");
348         BMO_HeaderFlag_To_Slot(bm, &dupeop, "geom", hflag, etypeflag);
349
350         BMO_Exec_Op(bm, &dupeop);
351         BMO_Finish_Op(bm, &dupeop);
352 }
353
354 /*
355  * Split Operator
356  *
357  * Duplicates verts, edges and faces of a mesh but also deletes the originals.
358  *
359  * INPUT SLOTS:
360  *
361  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
362  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
363  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
364  *
365  * OUTPUT SLOTS:
366  *
367  * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
368  * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
369  * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
370  */
371
372 #define SPLIT_INPUT     1
373 void splitop_exec(BMesh *bm, BMOperator *op)
374 {
375         BMOperator *splitop = op;
376         BMOperator dupeop;
377         BMOperator delop;
378         BMVert *v;
379         BMEdge *e;
380         BMFace *f;
381         BMIter iter, iter2;
382         int found;
383
384         /* initialize our sub-operator */
385         BMO_Init_Op(bm, &dupeop, "dupe");
386         BMO_Init_Op(bm, &delop, "del");
387         
388         BMO_CopySlot(splitop, &dupeop, "geom", "geom");
389         BMO_Exec_Op(bm, &dupeop);
390         
391         BMO_Flag_Buffer(bm, splitop, "geom", SPLIT_INPUT, BM_ALL);
392
393         /* make sure to remove edges and verts we don't need */
394         for (e = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e = BMIter_Step(&iter)) {
395                 found = 0;
396                 f = BMIter_New(&iter2, bm, BM_FACES_OF_EDGE, e);
397                 for ( ; f; f = BMIter_Step(&iter2)) {
398                         if (!BMO_TestFlag(bm, f, SPLIT_INPUT)) {
399                                 found = 1;
400                                 break;
401                         }
402                 }
403                 if (!found) BMO_SetFlag(bm, e, SPLIT_INPUT);
404         }
405         
406         for (v = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v = BMIter_Step(&iter)) {
407                 found = 0;
408                 e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, v);
409                 for ( ; e; e = BMIter_Step(&iter2)) {
410                         if (!BMO_TestFlag(bm, e, SPLIT_INPUT)) {
411                                 found = 1;
412                                 break;
413                         }
414                 }
415                 if (!found) BMO_SetFlag(bm, v, SPLIT_INPUT);
416
417         }
418
419         /* connect outputs of dupe to delete, exluding keep geometr */
420         BMO_Set_Int(&delop, "context", DEL_FACES);
421         BMO_Flag_To_Slot(bm, &delop, "geom", SPLIT_INPUT, BM_ALL);
422         
423         BMO_Exec_Op(bm, &delop);
424
425         /* now we make our outputs by copying the dupe output */
426         BMO_CopySlot(&dupeop, splitop, "newout", "geomout");
427         BMO_CopySlot(&dupeop, splitop, "boundarymap",
428                      "boundarymap");
429         BMO_CopySlot(&dupeop, splitop, "isovertmap",
430                      "isovertmap");
431         
432         /* cleanu */
433         BMO_Finish_Op(bm, &delop);
434         BMO_Finish_Op(bm, &dupeop);
435 }
436
437 #define DEL_INPUT               1
438 #define DEL_WIREVERT    2
439
440 static void delete_verts(BMesh *bm);
441 static void delete_context(BMesh *bm, int type);
442
443 void delop_exec(BMesh *bm, BMOperator *op)
444 {
445         BMOperator *delop = op;
446
447         /* Mark Buffer */
448         BMO_Flag_Buffer(bm, delop, "geom", DEL_INPUT, BM_ALL);
449
450         delete_context(bm, BMO_Get_Int(op, "context"));
451 }
452
453 static void delete_verts(BMesh *bm)
454 {
455         BMVert *v;
456         BMEdge *e;
457         BMLoop *f;
458         
459         BMIter verts;
460         BMIter edges;
461         BMIter faces;
462         
463         for (v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)) {
464                 if (BMO_TestFlag(bm, (BMHeader *)v, DEL_INPUT)) {
465                         /* Visit edge */
466                         for (e = BMIter_New(&edges, bm, BM_EDGES_OF_VERT, v); e; e = BMIter_Step(&edges))
467                                 BMO_SetFlag(bm, (BMHeader *)e, DEL_INPUT);
468                         /* Visit face */
469                         for (f = BMIter_New(&faces, bm, BM_FACES_OF_VERT, v); f; f = BMIter_Step(&faces))
470                                 BMO_SetFlag(bm, (BMHeader *)f, DEL_INPUT);
471                 }
472         }
473
474         BM_remove_tagged_faces(bm, DEL_INPUT);
475         BM_remove_tagged_edges(bm, DEL_INPUT);
476         BM_remove_tagged_verts(bm, DEL_INPUT);
477 }
478
479 static void delete_edges(BMesh *bm)
480 {
481         BMEdge *e;
482         BMFace *f;
483         
484         BMIter edges;
485         BMIter faces;
486
487         for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) {
488                 if (BMO_TestFlag(bm, (BMHeader *)e, DEL_INPUT)) {
489                         for (f = BMIter_New(&faces, bm, BM_FACES_OF_EDGE, e); f; f = BMIter_Step(&faces)) {
490                                         BMO_SetFlag(bm, (BMHeader *)f, DEL_INPUT);
491                         }
492                 }
493         }
494         BM_remove_tagged_faces(bm, DEL_INPUT);
495         BM_remove_tagged_edges(bm, DEL_INPUT);
496 }
497
498 /* you need to make remove tagged verts/edges/faces
499  * api functions that take a filter callback.....
500  * and this new filter type will be for opstack flags.
501  * This is because the BM_remove_taggedXXX functions bypass iterator API.
502  *  - Ops dont care about 'UI' considerations like selection state, hide state, ect.
503  *    If you want to work on unhidden selections for instance,
504  *    copy output from a 'select context' operator to another operator....
505  */
506
507 /* Break this into smaller functions */
508
509 static void delete_context(BMesh *bm, int type)
510 {
511         BMVert *v;
512         BMEdge *e;
513         BMFace *f;
514
515         BMIter verts;
516         BMIter edges;
517         BMIter faces;
518         
519         if (type == DEL_VERTS) delete_verts(bm);
520         else if (type == DEL_EDGES) {
521                 /* flush down to vert */
522                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) {
523                         if (BMO_TestFlag(bm, (BMHeader *)e, DEL_INPUT)) {
524                                 BMO_SetFlag(bm, (BMHeader *)(e->v1), DEL_INPUT);
525                                 BMO_SetFlag(bm, (BMHeader *)(e->v2), DEL_INPUT);
526                         }
527                 }
528                 delete_edges(bm);
529                 /* remove loose vertice */
530                 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)) {
531                         if (BMO_TestFlag(bm, (BMHeader *)v, DEL_INPUT) && (!(v->e)))
532                                 BMO_SetFlag(bm, (BMHeader *)v, DEL_WIREVERT);
533                 }
534                 BM_remove_tagged_verts(bm, DEL_WIREVERT);
535         }
536         else if (type == DEL_EDGESFACES) delete_edges(bm);
537         else if (type == DEL_ONLYFACES) BM_remove_tagged_faces(bm, DEL_INPUT);
538         else if (type == DEL_ONLYTAGGED) {
539                 BM_remove_tagged_faces(bm, DEL_INPUT);
540                 BM_remove_tagged_edges(bm, DEL_INPUT);
541                 BM_remove_tagged_verts(bm, DEL_INPUT);
542         }
543         else if (type == DEL_FACES) {
544                 /* go through and mark all edges and all verts of all faces for delet */
545                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) {
546                         if (BMO_TestFlag(bm, (BMHeader *)f, DEL_INPUT)) {
547                                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges))
548                                         BMO_SetFlag(bm, (BMHeader *)e, DEL_INPUT);
549                                 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts))
550                                         BMO_SetFlag(bm, (BMHeader *)v, DEL_INPUT);
551                         }
552                 }
553                 /* now go through and mark all remaining faces all edges for keeping */
554                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) {
555                         if (!BMO_TestFlag(bm, (BMHeader *)f, DEL_INPUT)) {
556                                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges)) {
557                                         BMO_ClearFlag(bm, (BMHeader *)e, DEL_INPUT);
558                                 }
559                                 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts)) {
560                                         BMO_ClearFlag(bm, (BMHeader *)v, DEL_INPUT);
561                                 }
562                         }
563                 }
564                 /* also mark all the vertices of remaining edges for keeping */
565                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) {
566                         if (!BMO_TestFlag(bm, (BMHeader *)e, DEL_INPUT)) {
567                                 BMO_ClearFlag(bm, (BMHeader *)e->v1, DEL_INPUT);
568                                 BMO_ClearFlag(bm, (BMHeader *)e->v2, DEL_INPUT);
569                         }
570                 }
571                 /* now delete marked face */
572                 BM_remove_tagged_faces(bm, DEL_INPUT);
573                 /* delete marked edge */
574                 BM_remove_tagged_edges(bm, DEL_INPUT);
575                 /* remove loose vertice */
576                 BM_remove_tagged_verts(bm, DEL_INPUT);
577         }
578         /* does this option even belong in here */
579         else if (type == DEL_ALL) {
580                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces))
581                         BMO_SetFlag(bm, (BMHeader *)f, DEL_INPUT);
582                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges))
583                         BMO_SetFlag(bm, (BMHeader *)e, DEL_INPUT);
584                 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts))
585                         BMO_SetFlag(bm, (BMHeader *)v, DEL_INPUT);
586                 
587                 BM_remove_tagged_faces(bm, DEL_INPUT);
588                 BM_remove_tagged_edges(bm, DEL_INPUT);
589                 BM_remove_tagged_verts(bm, DEL_INPUT);
590         }
591 }
592
593 /*
594  * Spin Operator
595  *
596  * Extrude or duplicate geometry a number of times,
597  * rotating and possibly translating after each step
598  */
599
600 void spinop_exec(BMesh *bm, BMOperator *op)
601 {
602     BMOperator dupop, extop;
603         float cent[3], dvec[3];
604         float axis[3] = {0.0f, 0.0f, 1.0f};
605         float q[4];
606         float rmat[3][3];
607         float phi, si;
608         int steps, dupli, a, usedvec;
609
610         BMO_Get_Vec(op, "cent", cent);
611         BMO_Get_Vec(op, "axis", axis);
612         normalize_v3(axis);
613         BMO_Get_Vec(op, "dvec", dvec);
614         usedvec = !is_zero_v3(dvec);
615         steps = BMO_Get_Int(op, "steps");
616         phi = BMO_Get_Float(op, "ang") * (float)M_PI / (360.0f * steps);
617         dupli = BMO_Get_Int(op, "dupli");
618
619         si = (float)sin(phi);
620         q[0] = (float)cos(phi);
621         q[1] = axis[0]*si;
622         q[2] = axis[1]*si;
623         q[3] = axis[2]*si;
624         quat_to_mat3(rmat, q);
625
626         BMO_CopySlot(op, op, "geom", "lastout");
627         for (a = 0; a < steps; a++) {
628                 if (dupli) {
629                         BMO_InitOpf(bm, &dupop, "dupe geom=%s", op, "lastout");
630                         BMO_Exec_Op(bm, &dupop);
631                         BMO_CallOpf(bm, "rotate cent=%v mat=%m3 verts=%s",
632                                 cent, rmat, &dupop, "newout");
633                         BMO_CopySlot(&dupop, op, "newout", "lastout");
634                         BMO_Finish_Op(bm, &dupop);
635                 }
636                 else {
637                         BMO_InitOpf(bm, &extop, "extrudefaceregion edgefacein=%s",
638                                 op, "lastout");
639                         BMO_Exec_Op(bm, &extop);
640                         BMO_CallOpf(bm, "rotate cent=%v mat=%m3 verts=%s",
641                                 cent, rmat, &extop, "geomout");
642                         BMO_CopySlot(&extop, op, "geomout", "lastout");
643                         BMO_Finish_Op(bm, &extop);
644                 }
645
646                 if (usedvec)
647                         BMO_CallOpf(bm, "translate vec=%v verts=%s", dvec, op, "lastout");
648         }
649 }