7f13731dc022e833b43977fe876963fdaa48edd6
[blender.git] / source / blender / bmesh / operators / bmo_dupe.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 /** \file blender/bmesh/operators/bmo_dupe.c
24  *  \ingroup bmesh
25  *
26  * Duplicate, Split, Split operators.
27  */
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_math.h"
32 #include "BLI_alloca.h"
33
34 #include "bmesh.h"
35
36 #include "intern/bmesh_operators_private.h" /* own include */
37
38 /* local flag define */
39 #define DUPE_INPUT      1 /* input from operator */
40 #define DUPE_NEW        2
41 #define DUPE_DONE       4
42 // #define DUPE_MAPPED     8 // UNUSED
43
44 /**
45  * COPY VERTEX
46  *
47  * Copy an existing vertex from one bmesh to another.
48  */
49 static BMVert *bmo_vert_copy(
50         BMOperator *op,
51         BMOpSlot *slot_vertmap_out,
52         BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash)
53 {
54         BMVert *v_dst;
55
56         /* Create a new vertex */
57         v_dst = BM_vert_create(bm_dst, v_src->co, NULL, BM_CREATE_SKIP_CD);
58         BMO_slot_map_elem_insert(op, slot_vertmap_out, v_src, v_dst);
59         BMO_slot_map_elem_insert(op, slot_vertmap_out, v_dst, v_src);
60
61         /* Insert new vertex into the vert hash */
62         BLI_ghash_insert(vhash, v_src, v_dst);
63
64         /* Copy attributes */
65         BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst);
66
67         /* Mark the vert for output */
68         BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW);
69
70         return v_dst;
71 }
72
73 /**
74  * COPY EDGE
75  *
76  * Copy an existing edge from one bmesh to another.
77  */
78 static BMEdge *bmo_edge_copy(
79         BMOperator *op,
80         BMOpSlot *slot_edgemap_out,
81         BMOpSlot *slot_boundarymap_out,
82         BMesh *bm_dst, BMesh *bm_src,
83         BMEdge *e_src,
84         GHash *vhash, GHash *ehash)
85 {
86         BMEdge *e_dst;
87         BMVert *e_dst_v1, *e_dst_v2;
88         uint rlen;
89
90         /* see if any of the neighboring faces are
91          * not being duplicated.  in that case,
92          * add it to the new/old map. */
93         /* lookup edge */
94         rlen = 0;
95         if (e_src->l) {
96                 BMLoop *l_iter_src, *l_first_src;
97                 l_iter_src = l_first_src = e_src->l;
98                 do {
99                         if (BMO_face_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) {
100                                 rlen++;
101                         }
102                 } while ((l_iter_src = l_iter_src->radial_next) != l_first_src);
103         }
104
105         /* Lookup v1 and v2 */
106         e_dst_v1 = BLI_ghash_lookup(vhash, e_src->v1);
107         e_dst_v2 = BLI_ghash_lookup(vhash, e_src->v2);
108
109         /* Create a new edge */
110         e_dst = BM_edge_create(bm_dst, e_dst_v1, e_dst_v2, NULL, BM_CREATE_SKIP_CD);
111         BMO_slot_map_elem_insert(op, slot_edgemap_out, e_src, e_dst);
112         BMO_slot_map_elem_insert(op, slot_edgemap_out, e_dst, e_src);
113
114         /* add to new/old edge map if necassary */
115         if (rlen < 2) {
116                 /* not sure what non-manifold cases of greater than three
117                  * radial should do. */
118                 BMO_slot_map_elem_insert(op, slot_boundarymap_out, e_src, e_dst);
119         }
120
121         /* Insert new edge into the edge hash */
122         BLI_ghash_insert(ehash, e_src, e_dst);
123
124         /* Copy attributes */
125         BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst);
126
127         /* Mark the edge for output */
128         BMO_edge_flag_enable(bm_dst, e_dst, DUPE_NEW);
129
130         return e_dst;
131 }
132
133 /**
134  * COPY FACE
135  *
136  * Copy an existing face from one bmesh to another.
137  */
138 static BMFace *bmo_face_copy(
139         BMOperator *op,
140         BMOpSlot *slot_facemap_out,
141         BMesh *bm_dst, BMesh *bm_src,
142         BMFace *f_src,
143         GHash *vhash, GHash *ehash)
144 {
145         BMFace *f_dst;
146         BMVert **vtar = BLI_array_alloca(vtar, f_src->len);
147         BMEdge **edar = BLI_array_alloca(edar, f_src->len);
148         BMLoop *l_iter_src, *l_iter_dst, *l_first_src;
149         int i;
150
151         l_first_src = BM_FACE_FIRST_LOOP(f_src);
152
153         /* lookup edge */
154         l_iter_src = l_first_src;
155         i = 0;
156         do {
157                 vtar[i] = BLI_ghash_lookup(vhash, l_iter_src->v);
158                 edar[i] = BLI_ghash_lookup(ehash, l_iter_src->e);
159                 i++;
160         } while ((l_iter_src = l_iter_src->next) != l_first_src);
161
162         /* create new face */
163         f_dst = BM_face_create(bm_dst, vtar, edar, f_src->len, NULL, BM_CREATE_SKIP_CD);
164         BMO_slot_map_elem_insert(op, slot_facemap_out, f_src, f_dst);
165         BMO_slot_map_elem_insert(op, slot_facemap_out, f_dst, f_src);
166
167         /* Copy attributes */
168         BM_elem_attrs_copy(bm_src, bm_dst, f_src, f_dst);
169
170         /* copy per-loop custom data */
171         l_iter_src = l_first_src;
172         l_iter_dst = BM_FACE_FIRST_LOOP(f_dst);
173         do {
174                 BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst);
175         } while ((void)
176                  (l_iter_dst = l_iter_dst->next),
177                  (l_iter_src = l_iter_src->next) != l_first_src);
178
179         /* Mark the face for output */
180         BMO_face_flag_enable(bm_dst, f_dst, DUPE_NEW);
181
182         return f_dst;
183 }
184
185 /**
186  * COPY MESH
187  *
188  * Internal Copy function.
189  */
190 static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
191 {
192         const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
193
194         BMVert *v = NULL, *v2;
195         BMEdge *e = NULL;
196         BMFace *f = NULL;
197
198         BMIter viter, eiter, fiter;
199         GHash *vhash, *ehash;
200
201         BMOpSlot *slot_boundary_map_out = BMO_slot_get(op->slots_out, "boundary_map.out");
202         BMOpSlot *slot_isovert_map_out  = BMO_slot_get(op->slots_out, "isovert_map.out");
203
204         BMOpSlot *slot_vert_map_out = BMO_slot_get(op->slots_out, "vert_map.out");
205         BMOpSlot *slot_edge_map_out = BMO_slot_get(op->slots_out, "edge_map.out");
206         BMOpSlot *slot_face_map_out = BMO_slot_get(op->slots_out, "face_map.out");
207
208         /* initialize pointer hashes */
209         vhash = BLI_ghash_ptr_new("bmesh dupeops v");
210         ehash = BLI_ghash_ptr_new("bmesh dupeops e");
211
212         /* duplicate flagged vertices */
213         BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) {
214                 if (BMO_vert_flag_test(bm_src, v, DUPE_INPUT) &&
215                     BMO_vert_flag_test(bm_src, v, DUPE_DONE) == false)
216                 {
217                         BMIter iter;
218                         bool isolated = true;
219
220                         v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash);
221
222                         BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
223                                 if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) {
224                                         isolated = false;
225                                         break;
226                                 }
227                         }
228
229                         if (isolated) {
230                                 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
231                                         if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT)) {
232                                                 isolated = false;
233                                                 break;
234                                         }
235                                 }
236                         }
237
238                         if (isolated) {
239                                 BMO_slot_map_elem_insert(op, slot_isovert_map_out, v, v2);
240                         }
241
242                         BMO_vert_flag_enable(bm_src, v, DUPE_DONE);
243                 }
244         }
245
246         /* now we dupe all the edges */
247         BM_ITER_MESH (e, &eiter, bm_src, BM_EDGES_OF_MESH) {
248                 if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT) &&
249                     BMO_edge_flag_test(bm_src, e, DUPE_DONE) == false)
250                 {
251                         /* make sure that verts are copied */
252                         if (!BMO_vert_flag_test(bm_src, e->v1, DUPE_DONE)) {
253                                 bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash);
254                                 BMO_vert_flag_enable(bm_src, e->v1, DUPE_DONE);
255                         }
256                         if (!BMO_vert_flag_test(bm_src, e->v2, DUPE_DONE)) {
257                                 bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash);
258                                 BMO_vert_flag_enable(bm_src, e->v2, DUPE_DONE);
259                         }
260                         /* now copy the actual edge */
261                         bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out,
262                                       bm_dst, bm_src, e, vhash, ehash);
263                         BMO_edge_flag_enable(bm_src, e, DUPE_DONE);
264                 }
265         }
266
267         /* first we dupe all flagged faces and their elements from source */
268         BM_ITER_MESH (f, &fiter, bm_src, BM_FACES_OF_MESH) {
269                 if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) {
270                         /* vertex pass */
271                         BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
272                                 if (!BMO_vert_flag_test(bm_src, v, DUPE_DONE)) {
273                                         bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash);
274                                         BMO_vert_flag_enable(bm_src, v, DUPE_DONE);
275                                 }
276                         }
277
278                         /* edge pass */
279                         BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
280                                 if (!BMO_edge_flag_test(bm_src, e, DUPE_DONE)) {
281                                         bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out,
282                                                       bm_dst, bm_src, e, vhash, ehash);
283                                         BMO_edge_flag_enable(bm_src, e, DUPE_DONE);
284                                 }
285                         }
286
287                         bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash);
288                         BMO_face_flag_enable(bm_src, f, DUPE_DONE);
289                 }
290         }
291
292         /* free pointer hashes */
293         BLI_ghash_free(vhash, NULL, NULL);
294         BLI_ghash_free(ehash, NULL, NULL);
295
296         if (use_select_history) {
297                 BLI_assert(bm_src == bm_dst);
298                 BMO_mesh_selected_remap(
299                         bm_dst,
300                         slot_vert_map_out,
301                         slot_edge_map_out,
302                         slot_face_map_out,
303                         false);
304         }
305 }
306
307 /**
308  * Duplicate Operator
309  *
310  * Duplicates verts, edges and faces of a mesh.
311  *
312  * INPUT SLOTS:
313  *
314  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated
315  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated
316  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated
317  *
318  * OUTPUT SLOTS:
319  *
320  * BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices
321  * BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges
322  * BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces
323  * BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices
324  * BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges
325  * BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces
326  */
327 void bmo_duplicate_exec(BMesh *bm, BMOperator *op)
328 {
329         BMOperator *dupeop = op;
330         BMesh *bm_dst = BMO_slot_ptr_get(op->slots_in, "dest");
331
332         if (!bm_dst)
333                 bm_dst = bm;
334
335         /* flag input */
336         BMO_slot_buffer_flag_enable(bm, dupeop->slots_in, "geom", BM_ALL_NOLOOP, DUPE_INPUT);
337
338         /* use the internal copy function */
339         bmo_mesh_copy(dupeop, bm_dst, bm);
340
341         /* Output */
342         /* First copy the input buffers to output buffers - original data */
343         BMO_slot_copy(dupeop, slots_in,  "geom",
344                       dupeop, slots_out, "geom_orig.out");
345
346         /* Now alloc the new output buffers */
347         BMO_slot_buffer_from_enabled_flag(bm, dupeop, dupeop->slots_out, "geom.out", BM_ALL_NOLOOP, DUPE_NEW);
348 }
349
350 #if 0 /* UNUSED */
351 /* executes the duplicate operation, feeding elements of
352  * type flag etypeflag and header flag flag to it.  note,
353  * to get more useful information (such as the mapping from
354  * original to new elements) you should run the dupe op manually */
355 void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag)
356 {
357         BMOperator dupeop;
358
359         BMO_op_init(bm, &dupeop, "duplicate");
360         BMO_slot_buffer_from_enabled_hflag(bm, &dupeop, "geom", htype, hflag);
361
362         BMO_op_exec(bm, &dupeop);
363         BMO_op_finish(bm, &dupeop);
364 }
365 #endif
366
367 /**
368  * Split Operator
369  *
370  * Duplicates verts, edges and faces of a mesh but also deletes the originals.
371  *
372  * INPUT SLOTS:
373  *
374  * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
375  * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
376  * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
377  *
378  * OUTPUT SLOTS:
379  *
380  * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
381  * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
382  * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
383  *
384  * \note Lower level uses of this operator may want to use #BM_mesh_separate_faces
385  * Since it's faster for the 'use_only_faces' case.
386  *
387  */
388 void bmo_split_exec(BMesh *bm, BMOperator *op)
389 {
390 #define SPLIT_INPUT 1
391
392         BMOperator *splitop = op;
393         BMOperator dupeop;
394         const bool use_only_faces = BMO_slot_bool_get(op->slots_in, "use_only_faces");
395
396         /* initialize our sub-operator */
397         BMO_op_init(bm, &dupeop, op->flag, "duplicate");
398
399         BMO_slot_copy(splitop, slots_in, "geom",
400                       &dupeop, slots_in, "geom");
401         BMO_op_exec(bm, &dupeop);
402
403         BMO_slot_buffer_flag_enable(bm, splitop->slots_in, "geom", BM_ALL_NOLOOP, SPLIT_INPUT);
404
405         if (use_only_faces) {
406                 BMVert *v;
407                 BMEdge *e;
408                 BMFace *f;
409                 BMIter iter, iter2;
410
411                 /* make sure to remove edges and verts we don't need */
412                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
413                         bool found = false;
414                         BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) {
415                                 if (!BMO_face_flag_test(bm, f, SPLIT_INPUT)) {
416                                         found = true;
417                                         break;
418                                 }
419                         }
420                         if (found == false) {
421                                 BMO_edge_flag_enable(bm, e, SPLIT_INPUT);
422                         }
423                 }
424
425                 BM_ITER_MESH (v, &iter, bm,  BM_VERTS_OF_MESH) {
426                         bool found = false;
427                         BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
428                                 if (!BMO_edge_flag_test(bm, e, SPLIT_INPUT)) {
429                                         found = true;
430                                         break;
431                                 }
432                         }
433                         if (found == false) {
434                                 BMO_vert_flag_enable(bm, v, SPLIT_INPUT);
435                         }
436                 }
437         }
438
439         /* connect outputs of dupe to delete, exluding keep geometry */
440         BMO_mesh_delete_oflag_context(bm, SPLIT_INPUT, DEL_FACES);
441
442         /* now we make our outputs by copying the dupe output */
443         BMO_slot_copy(&dupeop, slots_out, "geom.out",
444                       splitop, slots_out, "geom.out");
445
446         /* cleanup */
447         BMO_op_finish(bm, &dupeop);
448
449 #undef SPLIT_INPUT
450 }
451
452
453 void bmo_delete_exec(BMesh *bm, BMOperator *op)
454 {
455 #define DEL_INPUT 1
456
457         BMOperator *delop = op;
458
459         /* Mark Buffer */
460         BMO_slot_buffer_flag_enable(bm, delop->slots_in, "geom", BM_ALL_NOLOOP, DEL_INPUT);
461
462         BMO_mesh_delete_oflag_context(bm, DEL_INPUT, BMO_slot_int_get(op->slots_in, "context"));
463
464 #undef DEL_INPUT
465 }
466
467 /**
468  * Spin Operator
469  *
470  * Extrude or duplicate geometry a number of times,
471  * rotating and possibly translating after each step
472  */
473 void bmo_spin_exec(BMesh *bm, BMOperator *op)
474 {
475         BMOperator dupop, extop;
476         float cent[3], dvec[3];
477         float axis[3];
478         float rmat[3][3];
479         float phi;
480         int steps, do_dupli, a;
481         bool use_dvec;
482
483         BMO_slot_vec_get(op->slots_in, "cent", cent);
484         BMO_slot_vec_get(op->slots_in, "axis", axis);
485         normalize_v3(axis);
486         BMO_slot_vec_get(op->slots_in, "dvec", dvec);
487         use_dvec = !is_zero_v3(dvec);
488         steps    = BMO_slot_int_get(op->slots_in,   "steps");
489         phi      = BMO_slot_float_get(op->slots_in, "angle") / steps;
490         do_dupli = BMO_slot_bool_get(op->slots_in,  "use_duplicate");
491         const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
492         /* Caller needs to perform other sanity checks (such as the spin being 360d). */
493         const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge") && steps >= 3;
494
495         axis_angle_normalized_to_mat3(rmat, axis, phi);
496
497         BMVert **vtable = NULL;
498         if (use_merge) {
499                 vtable = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
500                 int i = 0;
501                 BMIter iter;
502                 BMVert *v;
503                 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
504                         vtable[i] = v;
505                         /* Evil! store original index in normal,
506                          * this is duplicated into every other vertex.
507                          * So we can read the original from the final.
508                          *
509                          * The normals must be recalculated anyway. */
510                         *((int *)&v->no[0]) = i;
511                 }
512         }
513
514         BMO_slot_copy(op, slots_in,  "geom",
515                       op, slots_out, "geom_last.out");
516         for (a = 0; a < steps; a++) {
517                 if (do_dupli) {
518                         BMO_op_initf(bm, &dupop, op->flag, "duplicate geom=%S", op, "geom_last.out");
519                         BMO_op_exec(bm, &dupop);
520                         BMO_op_callf(bm, op->flag,
521                                      "rotate cent=%v matrix=%m3 space=%s verts=%S",
522                                      cent, rmat, op, "space", &dupop, "geom.out");
523                         BMO_slot_copy(&dupop, slots_out, "geom.out",
524                                       op,     slots_out, "geom_last.out");
525                         BMO_op_finish(bm, &dupop);
526                 }
527                 else {
528                         BMO_op_initf(bm, &extop, op->flag, "extrude_face_region geom=%S use_normal_flip=%b",
529                                      op, "geom_last.out", use_normal_flip && (a == 0));
530                         BMO_op_exec(bm, &extop);
531                         if ((use_merge && (a == steps - 1)) == false) {
532                                 BMO_op_callf(bm, op->flag,
533                                              "rotate cent=%v matrix=%m3 space=%s verts=%S",
534                                              cent, rmat, op, "space", &extop, "geom.out");
535                                 BMO_slot_copy(&extop, slots_out, "geom.out",
536                                               op,     slots_out, "geom_last.out");
537                         }
538                         else {
539                                 /* Merge first/last vertices and edges (maintaining 'geom.out' state). */
540                                 BMOpSlot *slot_geom_out = BMO_slot_get(extop.slots_out, "geom.out");
541                                 BMElem  **elem_array = (BMElem **)slot_geom_out->data.buf;
542                                 int elem_array_len = slot_geom_out->len;
543                                 for (int i = 0; i < elem_array_len; ) {
544                                         if (elem_array[i]->head.htype == BM_VERT) {
545                                                 BMVert *v_src = (BMVert *)elem_array[i];
546                                                 BMVert *v_dst = vtable[*((const int *)&v_src->no[0])];
547                                                 BM_vert_splice(bm, v_dst, v_src);
548                                                 elem_array_len--;
549                                                 elem_array[i] = elem_array[elem_array_len];
550                                         }
551                                         else {
552                                                 i++;
553                                         }
554                                 }
555                                 for (int i = 0; i < elem_array_len; ) {
556                                         if (elem_array[i]->head.htype == BM_EDGE) {
557                                                 BMEdge *e_src = (BMEdge *)elem_array[i];
558                                                 BMEdge *e_dst = BM_edge_find_double(e_src);
559                                                 BM_edge_splice(bm, e_dst, e_src);
560                                                 elem_array_len--;
561                                                 elem_array[i] = elem_array[elem_array_len];
562                                         }
563                                         else {
564                                                 i++;
565                                         }
566                                 }
567                                 /* Full copies of faces may cause overlap. */
568                                 for (int i = 0; i < elem_array_len; ) {
569                                         if (elem_array[i]->head.htype == BM_FACE) {
570                                                 BMFace *f_src = (BMFace *)elem_array[i];
571                                                 BMFace *f_dst = BM_face_find_double(f_src);
572                                                 if (f_dst != NULL) {
573                                                         BM_face_kill(bm, f_src);
574                                                         elem_array_len--;
575                                                         elem_array[i] = elem_array[elem_array_len];
576                                                         continue;
577                                                 }
578                                         }
579                                         i++;
580                                 }
581                                 slot_geom_out->len = elem_array_len;
582                         }
583                         BMO_op_finish(bm, &extop);
584                 }
585
586                 if (use_dvec) {
587                         mul_m3_v3(rmat, dvec);
588                         BMO_op_callf(bm, op->flag,
589                                      "translate vec=%v space=%s verts=%S",
590                                      dvec, op, "space", op, "geom_last.out");
591                 }
592         }
593
594         if (vtable) {
595                 MEM_freeN(vtable);
596         }
597 }