46ed74695715c2f66e4c1e6811d959a7636c0e99
[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                         BMO_SetFlag(source, (BMHeader *)v, DUPE_DONE);
234                 }
235         }
236
237         /* now we dupe all the edge */
238         for (e = BMIter_New(&edges, source, BM_EDGES_OF_MESH, source); e; e = BMIter_Step(&edges)) {
239                 if (BMO_TestFlag(source, (BMHeader *)e, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader *)e, DUPE_DONE))) {
240                         /* make sure that verts are copie */
241                         if (!BMO_TestFlag(source, (BMHeader *)e->v1, DUPE_DONE)) {
242                                 copy_vertex(source, e->v1, target, vhash);
243                                 BMO_SetFlag(source, (BMHeader *)e->v1, DUPE_DONE);
244                         }
245                         if (!BMO_TestFlag(source, (BMHeader *)e->v2, DUPE_DONE)) {
246                                 copy_vertex(source, e->v2, target, vhash);
247                                 BMO_SetFlag(source, (BMHeader *)e->v2, DUPE_DONE);
248                         }
249                         /* now copy the actual edg */
250                         copy_edge(op, source, e, target,  vhash,  ehash);                       
251                         BMO_SetFlag(source, (BMHeader *)e, DUPE_DONE);
252                 }
253         }
254
255         /* first we dupe all flagged faces and their elements from sourc */
256         for (f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f = BMIter_Step(&faces)) {
257                 if (BMO_TestFlag(source, (BMHeader *)f, DUPE_INPUT)) {
258                         /* vertex pas */
259                         for (v = BMIter_New(&verts, source, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts)) {
260                                 if (!BMO_TestFlag(source, (BMHeader *)v, DUPE_DONE)) {
261                                         copy_vertex(source, v, target, vhash);
262                                         BMO_SetFlag(source, (BMHeader *)v, DUPE_DONE);
263                                 }
264                         }
265
266                         /* edge pas */
267                         for (e = BMIter_New(&edges, source, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges)) {
268                                 if (!BMO_TestFlag(source, (BMHeader *)e, DUPE_DONE)) {
269                                         copy_edge(op, source, e, target,  vhash,  ehash);
270                                         BMO_SetFlag(source, (BMHeader *)e, DUPE_DONE);
271                                 }
272                         }
273
274                         /* ensure arrays are the right size */
275                         BLI_array_empty(vtar);
276                         BLI_array_empty(edar);
277
278                         BLI_array_growitems(vtar, f->len);
279                         BLI_array_growitems(edar, f->len);
280
281                         copy_face(op, source, f, target, vtar, edar, vhash, ehash);
282                         BMO_SetFlag(source, (BMHeader *)f, DUPE_DONE);
283                 }
284         }
285         
286         /* free pointer hashe */
287         BLI_ghash_free(vhash, NULL, NULL);
288         BLI_ghash_free(ehash, NULL, NULL);      
289
290         BLI_array_free(vtar); /* free vert pointer array */
291         BLI_array_free(edar); /* free edge pointer array */
292 }
293
294 /*
295  * Duplicate Operator
296  *
297  * Duplicates verts, edges and faces of a mesh.
298  *
299  * INPUT SLOTS:
300  *
301  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated
302  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated
303  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated
304  *
305  * OUTPUT SLOTS:
306  * 
307  * BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices
308  * BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges
309  * BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces
310  * BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices
311  * BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges
312  * BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces
313  *
314  */
315
316 void dupeop_exec(BMesh *bm, BMOperator *op)
317 {
318         BMOperator *dupeop = op;
319         BMesh *bm2 = BMO_Get_Pnt(op, "dest");
320         
321         if (!bm2)
322                 bm2 = bm;
323                 
324         /* flag inpu */
325         BMO_Flag_Buffer(bm, dupeop, "geom", DUPE_INPUT, BM_ALL);
326
327         /* use the internal copy functio */
328         copy_mesh(dupeop, bm, bm2);
329         
330         /* Outpu */
331         /* First copy the input buffers to output buffers - original dat */
332         BMO_CopySlot(dupeop, dupeop, "geom", "origout");
333
334         /* Now alloc the new output buffer */
335         BMO_Flag_To_Slot(bm, dupeop, "newout", DUPE_NEW, BM_ALL);
336 }
337
338 /* executes the duplicate operation, feeding elements of
339  * type flag etypeflag and header flag flag to it.  note,
340  * to get more useful information (such as the mapping from
341  * original to new elements) you should run the dupe op manually */
342 void BMOP_DupeFromFlag(BMesh *bm, int etypeflag, const char hflag)
343 {
344         BMOperator dupeop;
345
346         BMO_Init_Op(bm, &dupeop, "dupe");
347         BMO_HeaderFlag_To_Slot(bm, &dupeop, "geom", hflag, etypeflag);
348
349         BMO_Exec_Op(bm, &dupeop);
350         BMO_Finish_Op(bm, &dupeop);
351 }
352
353 /*
354  * Split Operator
355  *
356  * Duplicates verts, edges and faces of a mesh but also deletes the originals.
357  *
358  * INPUT SLOTS:
359  *
360  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
361  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
362  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
363  *
364  * OUTPUT SLOTS:
365  * 
366  * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
367  * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
368  * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
369  */
370
371 #define SPLIT_INPUT     1
372 void splitop_exec(BMesh *bm, BMOperator *op)
373 {
374         BMOperator *splitop = op;
375         BMOperator dupeop;
376         BMOperator delop;
377         BMVert *v;
378         BMEdge *e;
379         BMFace *f;
380         BMIter iter, iter2;
381         int found;
382
383         /* initialize our sub-operator */
384         BMO_Init_Op(bm, &dupeop, "dupe");
385         BMO_Init_Op(bm, &delop, "del");
386         
387         BMO_CopySlot(splitop, &dupeop, "geom", "geom");
388         BMO_Exec_Op(bm, &dupeop);
389         
390         BMO_Flag_Buffer(bm, splitop, "geom", SPLIT_INPUT, BM_ALL);
391
392         /* make sure to remove edges and verts we don't need */
393         for (e = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e = BMIter_Step(&iter)) {
394                 found = 0;
395                 f = BMIter_New(&iter2, bm, BM_FACES_OF_EDGE, e);
396                 for ( ; f; f = BMIter_Step(&iter2)) {
397                         if (!BMO_TestFlag(bm, f, SPLIT_INPUT)) {
398                                 found = 1;
399                                 break;
400                         }
401                 }
402                 if (!found) BMO_SetFlag(bm, e, SPLIT_INPUT);
403         }
404         
405         for (v = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v = BMIter_Step(&iter)) {
406                 found = 0;
407                 e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, v);
408                 for ( ; e; e = BMIter_Step(&iter2)) {
409                         if (!BMO_TestFlag(bm, e, SPLIT_INPUT)) {
410                                 found = 1;
411                                 break;
412                         }
413                 }
414                 if (!found) BMO_SetFlag(bm, v, SPLIT_INPUT);
415
416         }
417
418         /* connect outputs of dupe to delete, exluding keep geometr */
419         BMO_Set_Int(&delop, "context", DEL_FACES);
420         BMO_Flag_To_Slot(bm, &delop, "geom", SPLIT_INPUT, BM_ALL);
421         
422         BMO_Exec_Op(bm, &delop);
423
424         /* now we make our outputs by copying the dupe output */
425         BMO_CopySlot(&dupeop, splitop, "newout", "geomout");
426         BMO_CopySlot(&dupeop, splitop, "boundarymap",
427                      "boundarymap");
428         BMO_CopySlot(&dupeop, splitop, "isovertmap",
429                      "isovertmap");
430         
431         /* cleanu */
432         BMO_Finish_Op(bm, &delop);
433         BMO_Finish_Op(bm, &dupeop);
434 }
435
436 #define DEL_INPUT               1
437 #define DEL_WIREVERT    2
438
439 static void delete_verts(BMesh *bm);
440 static void delete_context(BMesh *bm, int type);
441
442 void delop_exec(BMesh *bm, BMOperator *op)
443 {
444         BMOperator *delop = op;
445
446         /* Mark Buffer */
447         BMO_Flag_Buffer(bm, delop, "geom", DEL_INPUT, BM_ALL);
448
449         delete_context(bm, BMO_Get_Int(op, "context"));
450 }
451
452 static void delete_verts(BMesh *bm)
453 {
454         BMVert *v;
455         BMEdge *e;
456         BMLoop *f;
457         
458         BMIter verts;
459         BMIter edges;
460         BMIter faces;
461         
462         for (v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)) {
463                 if (BMO_TestFlag(bm, (BMHeader *)v, DEL_INPUT)) {
464                         /* Visit edge */
465                         for (e = BMIter_New(&edges, bm, BM_EDGES_OF_VERT, v); e; e = BMIter_Step(&edges))
466                                 BMO_SetFlag(bm, (BMHeader *)e, DEL_INPUT);
467                         /* Visit face */
468                         for (f = BMIter_New(&faces, bm, BM_FACES_OF_VERT, v); f; f = BMIter_Step(&faces))
469                                 BMO_SetFlag(bm, (BMHeader *)f, DEL_INPUT);
470                 }
471         }
472
473         BM_remove_tagged_faces(bm, DEL_INPUT);
474         BM_remove_tagged_edges(bm, DEL_INPUT);
475         BM_remove_tagged_verts(bm, DEL_INPUT);
476 }
477
478 static void delete_edges(BMesh *bm)
479 {
480         BMEdge *e;
481         BMFace *f;
482         
483         BMIter edges;
484         BMIter faces;
485
486         for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) {
487                 if (BMO_TestFlag(bm, (BMHeader *)e, DEL_INPUT)) {
488                         for (f = BMIter_New(&faces, bm, BM_FACES_OF_EDGE, e); f; f = BMIter_Step(&faces)) {
489                                         BMO_SetFlag(bm, (BMHeader *)f, DEL_INPUT);
490                         }
491                 }
492         }
493         BM_remove_tagged_faces(bm, DEL_INPUT);
494         BM_remove_tagged_edges(bm, DEL_INPUT);
495 }
496
497 /* you need to make remove tagged verts/edges/faces
498  * api functions that take a filter callback.....
499  * and this new filter type will be for opstack flags.
500  * This is because the BM_remove_taggedXXX functions bypass iterator API.
501  *  - Ops dont care about 'UI' considerations like selection state, hide state, ect.
502  *    If you want to work on unhidden selections for instance,
503  *    copy output from a 'select context' operator to another operator....
504  */
505
506 /* Break this into smaller functions */
507
508 static void delete_context(BMesh *bm, int type)
509 {
510         BMVert *v;
511         BMEdge *e;
512         BMFace *f;
513
514         BMIter verts;
515         BMIter edges;
516         BMIter faces;
517         
518         if (type == DEL_VERTS) delete_verts(bm);
519         else if (type == DEL_EDGES) {
520                 /* flush down to vert */
521                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) {
522                         if (BMO_TestFlag(bm, (BMHeader *)e, DEL_INPUT)) {
523                                 BMO_SetFlag(bm, (BMHeader *)(e->v1), DEL_INPUT);
524                                 BMO_SetFlag(bm, (BMHeader *)(e->v2), DEL_INPUT);
525                         }
526                 }
527                 delete_edges(bm);
528                 /* remove loose vertice */
529                 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)) {
530                         if (BMO_TestFlag(bm, (BMHeader *)v, DEL_INPUT) && (!(v->e)))
531                                 BMO_SetFlag(bm, (BMHeader *)v, DEL_WIREVERT);
532                 }
533                 BM_remove_tagged_verts(bm, DEL_WIREVERT);
534         }
535         else if (type == DEL_EDGESFACES) delete_edges(bm);
536         else if (type == DEL_ONLYFACES) BM_remove_tagged_faces(bm, DEL_INPUT);
537         else if (type == DEL_ONLYTAGGED) {
538                 BM_remove_tagged_faces(bm, DEL_INPUT);
539                 BM_remove_tagged_edges(bm, DEL_INPUT);
540                 BM_remove_tagged_verts(bm, DEL_INPUT);
541         }
542         else if (type == DEL_FACES) {
543                 /* go through and mark all edges and all verts of all faces for delet */
544                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) {
545                         if (BMO_TestFlag(bm, (BMHeader *)f, DEL_INPUT)) {
546                                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges))
547                                         BMO_SetFlag(bm, (BMHeader *)e, DEL_INPUT);
548                                 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts))
549                                         BMO_SetFlag(bm, (BMHeader *)v, DEL_INPUT);
550                         }
551                 }
552                 /* now go through and mark all remaining faces all edges for keeping */
553                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) {
554                         if (!BMO_TestFlag(bm, (BMHeader *)f, DEL_INPUT)) {
555                                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges)) {
556                                         BMO_ClearFlag(bm, (BMHeader *)e, DEL_INPUT);
557                                 }
558                                 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts)) {
559                                         BMO_ClearFlag(bm, (BMHeader *)v, DEL_INPUT);
560                                 }
561                         }
562                 }
563                 /* also mark all the vertices of remaining edges for keeping */
564                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) {
565                         if (!BMO_TestFlag(bm, (BMHeader *)e, DEL_INPUT)) {
566                                 BMO_ClearFlag(bm, (BMHeader *)e->v1, DEL_INPUT);
567                                 BMO_ClearFlag(bm, (BMHeader *)e->v2, DEL_INPUT);
568                         }
569                 }
570                 /* now delete marked face */
571                 BM_remove_tagged_faces(bm, DEL_INPUT);
572                 /* delete marked edge */
573                 BM_remove_tagged_edges(bm, DEL_INPUT);
574                 /* remove loose vertice */
575                 BM_remove_tagged_verts(bm, DEL_INPUT);
576         }
577         /* does this option even belong in here */
578         else if (type == DEL_ALL) {
579                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces))
580                         BMO_SetFlag(bm, (BMHeader *)f, DEL_INPUT);
581                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges))
582                         BMO_SetFlag(bm, (BMHeader *)e, DEL_INPUT);
583                 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts))
584                         BMO_SetFlag(bm, (BMHeader *)v, DEL_INPUT);
585                 
586                 BM_remove_tagged_faces(bm, DEL_INPUT);
587                 BM_remove_tagged_edges(bm, DEL_INPUT);
588                 BM_remove_tagged_verts(bm, DEL_INPUT);
589         }
590 }
591
592 /*
593  * Spin Operator
594  *
595  * Extrude or duplicate geometry a number of times,
596  * rotating and possibly translating after each step
597  */
598
599 void spinop_exec(BMesh *bm, BMOperator *op)
600 {
601     BMOperator dupop, extop;
602         float cent[3], dvec[3];
603         float axis[3] = {0.0f, 0.0f, 1.0f};
604         float q[4];
605         float rmat[3][3];
606         float phi, si;
607         int steps, dupli, a, usedvec;
608
609         BMO_Get_Vec(op, "cent", cent);
610         BMO_Get_Vec(op, "axis", axis);
611         normalize_v3(axis);
612         BMO_Get_Vec(op, "dvec", dvec);
613         usedvec = !is_zero_v3(dvec);
614         steps = BMO_Get_Int(op, "steps");
615         phi = BMO_Get_Float(op, "ang") * (float)M_PI / (360.0f * steps);
616         dupli = BMO_Get_Int(op, "dupli");
617
618         si = (float)sin(phi);
619         q[0] = (float)cos(phi);
620         q[1] = axis[0]*si;
621         q[2] = axis[1]*si;
622         q[3] = axis[2]*si;
623         quat_to_mat3(rmat, q);
624
625         BMO_CopySlot(op, op, "geom", "lastout");
626         for (a = 0; a < steps; a++) {
627                 if (dupli) {
628                         BMO_InitOpf(bm, &dupop, "dupe geom=%s", op, "lastout");
629                         BMO_Exec_Op(bm, &dupop);
630                         BMO_CallOpf(bm, "rotate cent=%v mat=%m3 verts=%s",
631                                 cent, rmat, &dupop, "newout");
632                         BMO_CopySlot(&dupop, op, "newout", "lastout");
633                         BMO_Finish_Op(bm, &dupop);
634                 }
635                 else {
636                         BMO_InitOpf(bm, &extop, "extrudefaceregion edgefacein=%s",
637                                 op, "lastout");
638                         BMO_Exec_Op(bm, &extop);
639                         BMO_CallOpf(bm, "rotate cent=%v mat=%m3 verts=%s",
640                                 cent, rmat, &extop, "geomout");
641                         BMO_CopySlot(&extop, op, "geomout", "lastout");
642                         BMO_Finish_Op(bm, &extop);
643                 }
644
645                 if (usedvec)
646                         BMO_CallOpf(bm, "translate vec=%v verts=%s", dvec, op, "lastout");
647         }
648 }