Mempool: delay allocating an initial chunk, its not always used
[blender.git] / source / blender / bmesh / intern / bmesh_operators.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, Geoffrey Bantle, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/intern/bmesh_operators.c
24  *  \ingroup bmesh
25  *
26  * BMesh operator access.
27  */
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_utildefines.h"
32 #include "BLI_string.h"
33 #include "BLI_math.h"
34 #include "BLI_memarena.h"
35 #include "BLI_mempool.h"
36 #include "BLI_listbase.h"
37
38 #include "BLF_translation.h"
39
40 #include "bmesh.h"
41 #include "intern/bmesh_private.h"
42
43 /* forward declarations */
44 static void bmo_flag_layer_alloc(BMesh *bm);
45 static void bmo_flag_layer_free(BMesh *bm);
46 static void bmo_flag_layer_clear(BMesh *bm);
47 static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
48 static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
49
50 static const char *bmo_error_messages[] = {
51         NULL,
52         N_("Self intersection error"),
53         N_("Could not dissolve vert"),
54         N_("Could not connect vertices"),
55         N_("Could not traverse mesh"),
56         N_("Could not dissolve faces"),
57         N_("Could not dissolve vertices"),
58         N_("Tessellation error"),
59         N_("Cannot deal with non-manifold geometry"),
60         N_("Invalid selection"),
61         N_("Internal mesh error"),
62 };
63
64
65 /* operator slot type information - size of one element of the type given. */
66 const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = {
67         0,                      /*  0: BMO_OP_SLOT_SENTINEL */
68         sizeof(int),            /*  1: BMO_OP_SLOT_BOOL */ 
69         sizeof(int),            /*  2: BMO_OP_SLOT_INT */ 
70         sizeof(float),          /*  3: BMO_OP_SLOT_FLT */ 
71         sizeof(void *),         /*  4: BMO_OP_SLOT_PNT */ 
72         sizeof(void *),         /*  5: BMO_OP_SLOT_PNT */
73         0,                      /*  6: unused */
74         0,                      /*  7: unused */
75         sizeof(float) * 3,      /*  8: BMO_OP_SLOT_VEC */
76         sizeof(void *),         /*  9: BMO_OP_SLOT_ELEMENT_BUF */
77         sizeof(void *)          /* 10: BMO_OP_SLOT_MAPPING */
78 };
79
80 /* Dummy slot so there is something to return when slot name lookup fails */
81 // static BMOpSlot BMOpEmptySlot = {0};
82
83 void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
84 {
85         op->flag |= op_flag;
86 }
87
88 void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
89 {
90         op->flag &= ~op_flag;
91 }
92
93 /**
94  * \brief BMESH OPSTACK PUSH
95  *
96  * Pushes the opstack down one level and allocates a new flag layer if appropriate.
97  */
98 void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
99 {
100         bm->stackdepth++;
101
102         BLI_assert(bm->totflags > 0);
103
104         /* add flag layer, if appropriate */
105         if (bm->stackdepth > 1)
106                 bmo_flag_layer_alloc(bm);
107         else
108                 bmo_flag_layer_clear(bm);
109 }
110
111 /**
112  * \brief BMESH OPSTACK POP
113  *
114  * Pops the opstack one level and frees a flag layer if appropriate
115  *
116  * BMESH_TODO: investigate NOT freeing flag layers.
117  */
118 void BMO_pop(BMesh *bm)
119 {
120         if (bm->stackdepth > 1)
121                 bmo_flag_layer_free(bm);
122
123         bm->stackdepth--;
124 }
125
126
127 /* use for both slot_types_in and slot_types_out */
128 static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args)
129 {
130         BMOpSlot *slot;
131         unsigned int i;
132         for (i = 0; slot_types[i].type; i++) {
133                 slot = &slot_args[i];
134                 slot->slot_name    = slot_types[i].name;
135                 slot->slot_type    = slot_types[i].type;
136                 slot->slot_subtype = slot_types[i].subtype;
137                 // slot->index = i;  // UNUSED
138
139                 switch (slot->slot_type) {
140                         case BMO_OP_SLOT_MAPPING:
141                                 slot->data.ghash = BLI_ghash_ptr_new("bmesh slot map hash");
142                                 break;
143                         default:
144                                 break;
145                 }
146         }
147 }
148
149 static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args)
150 {
151         BMOpSlot *slot;
152         unsigned int i;
153         for (i = 0; slot_types[i].type; i++) {
154                 slot = &slot_args[i];
155                 switch (slot->slot_type) {
156                         case BMO_OP_SLOT_MAPPING:
157                                 BLI_ghash_free(slot->data.ghash, NULL, NULL);
158                                 break;
159                         default:
160                                 break;
161                 }
162         }
163 }
164
165 /**
166  * \brief BMESH OPSTACK INIT OP
167  *
168  * Initializes an operator structure to a certain type
169  */
170 void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
171 {
172         int opcode = BMO_opcode_from_opname(opname);
173
174 #ifdef DEBUG
175         BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
176 #else
177         (void)bm;
178 #endif
179
180         if (opcode == -1) {
181                 opcode = 0; /* error!, already printed, have a better way to handle this? */
182         }
183
184         memset(op, 0, sizeof(BMOperator));
185         op->type = opcode;
186         op->type_flag = bmo_opdefines[opcode]->type_flag;
187         op->flag = flag;
188         
189         /* initialize the operator slot types */
190         bmo_op_slots_init(bmo_opdefines[opcode]->slot_types_in,  op->slots_in);
191         bmo_op_slots_init(bmo_opdefines[opcode]->slot_types_out, op->slots_out);
192
193         /* callback */
194         op->exec = bmo_opdefines[opcode]->exec;
195
196         /* memarena, used for operator's slot buffers */
197         op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
198         BLI_memarena_use_calloc(op->arena);
199 }
200
201 /**
202  * \brief BMESH OPSTACK EXEC OP
203  *
204  * Executes a passed in operator.
205  *
206  * This handles the allocation and freeing of temporary flag
207  * layers and starting/stopping the modeling loop.
208  * Can be called from other operators exec callbacks as well.
209  */
210 void BMO_op_exec(BMesh *bm, BMOperator *op)
211 {
212         /* allocate tool flags on demand */
213         BM_mesh_elem_toolflags_ensure(bm);
214
215         BMO_push(bm, op);
216
217         if (bm->stackdepth == 2)
218                 bmesh_edit_begin(bm, op->type_flag);
219         op->exec(bm, op);
220         
221         if (bm->stackdepth == 2)
222                 bmesh_edit_end(bm, op->type_flag);
223         
224         BMO_pop(bm);
225 }
226
227 /**
228  * \brief BMESH OPSTACK FINISH OP
229  *
230  * Does housekeeping chores related to finishing up an operator.
231  */
232 void BMO_op_finish(BMesh *bm, BMOperator *op)
233 {
234         bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_in,  op->slots_in);
235         bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_out, op->slots_out);
236
237         BLI_memarena_free(op->arena);
238
239 #ifdef DEBUG
240         BM_ELEM_INDEX_VALIDATE(bm, "post bmo", bmo_opdefines[op->type]->opname);
241
242         /* avoid accidental re-use */
243         memset(op, 0xff, sizeof(*op));
244 #else
245         (void)bm;
246 #endif
247 }
248
249 /**
250  * \brief BMESH OPSTACK HAS SLOT
251  *
252  * \return Success if the slot if found.
253  */
254 bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
255 {
256         int slot_code = bmo_name_to_slotcode(slot_args, identifier);
257         return (slot_code >= 0);
258 }
259
260 /**
261  * \brief BMESH OPSTACK GET SLOT
262  *
263  * Returns a pointer to the slot of type 'slot_code'
264  */
265 BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
266 {
267         int slot_code = bmo_name_to_slotcode_check(slot_args, identifier);
268
269         if (UNLIKELY(slot_code < 0)) {
270                 //return &BMOpEmptySlot;
271                 BLI_assert(0);
272                 return NULL;  /* better crash */
273         }
274
275         return &slot_args[slot_code];
276 }
277
278 /**
279  * \brief BMESH OPSTACK COPY SLOT
280  *
281  * define used.
282  * Copies data from one slot to another.
283  */
284 void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
285                     BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
286                     struct MemArena *arena_dst)
287 {
288         BMOpSlot *slot_src = BMO_slot_get(slot_args_src, slot_name_src);
289         BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
290
291         if (slot_src == slot_dst)
292                 return;
293
294         BLI_assert(slot_src->slot_type == slot_dst->slot_type);
295         if (slot_src->slot_type != slot_dst->slot_type) {
296                 return;
297         }
298
299         if (slot_dst->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
300                 /* do buffer copy */
301                 slot_dst->data.buf = NULL;
302                 slot_dst->len = slot_src->len;
303                 if (slot_dst->len) {
304                         /* check dest has all flags enabled that the source has */
305                         const eBMOpSlotSubType_Elem src_elem_flag = (slot_src->slot_subtype.elem & BM_ALL_NOLOOP);
306                         const eBMOpSlotSubType_Elem dst_elem_flag = (slot_dst->slot_subtype.elem & BM_ALL_NOLOOP);
307
308                         if ((src_elem_flag | dst_elem_flag) == dst_elem_flag) {
309                                 /* pass */
310                         }
311                         else {
312                                 /* check types */
313                                 const unsigned int tot = slot_src->len;
314                                 unsigned int i;
315                                 unsigned int out = 0;
316                                 BMElem **ele_src = (BMElem **)slot_src->data.buf;
317                                 for (i = 0; i < tot; i++, ele_src++) {
318                                         if ((*ele_src)->head.htype & dst_elem_flag) {
319                                                 out++;
320                                         }
321                                 }
322                                 if (out != tot) {
323                                         slot_dst->len = out;
324                                 }
325                         }
326
327                         if (slot_dst->len) {
328                                 const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[slot_dst->slot_type] * slot_dst->len;
329                                 slot_dst->data.buf = BLI_memarena_alloc(arena_dst, slot_alloc_size);
330                                 if (slot_src->len == slot_dst->len) {
331                                         memcpy(slot_dst->data.buf, slot_src->data.buf, slot_alloc_size);
332                                 }
333                                 else {
334                                         /* only copy compatible elements */
335                                         const unsigned int tot = slot_src->len;
336                                         unsigned int i;
337                                         BMElem **ele_src = (BMElem **)slot_src->data.buf;
338                                         BMElem **ele_dst = (BMElem **)slot_dst->data.buf;
339                                         for (i = 0; i < tot; i++, ele_src++) {
340                                                 if ((*ele_src)->head.htype & dst_elem_flag) {
341                                                         *ele_dst = *ele_src;
342                                                         ele_dst++;
343                                                 }
344                                         }
345                                 }
346                         }
347                 }
348         }
349         else if (slot_dst->slot_type == BMO_OP_SLOT_MAPPING) {
350                 GHashIterator it;
351                 for (BLI_ghashIterator_init(&it, slot_src->data.ghash);
352                      BLI_ghashIterator_done(&it) == false;
353                      BLI_ghashIterator_step(&it))
354                 {
355                         void *key = BLI_ghashIterator_getKey(&it);
356                         void *val = BLI_ghashIterator_getValue(&it);
357                         BLI_ghash_insert(slot_dst->data.ghash, key, val);
358                 }
359         }
360         else {
361                 slot_dst->data = slot_src->data;
362         }
363 }
364
365 /*
366  * BMESH OPSTACK SET XXX
367  *
368  * Sets the value of a slot depending on it's type
369  */
370
371 void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float f)
372 {
373         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
374         BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
375         if (!(slot->slot_type == BMO_OP_SLOT_FLT))
376                 return;
377
378         slot->data.f = f;
379 }
380
381 void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i)
382 {
383         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
384         BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
385         if (!(slot->slot_type == BMO_OP_SLOT_INT))
386                 return;
387
388         slot->data.i = i;
389 }
390
391 void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i)
392 {
393         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
394         BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
395         if (!(slot->slot_type == BMO_OP_SLOT_BOOL))
396                 return;
397
398         slot->data.i = i;
399 }
400
401 /* only supports square mats */
402 void BMO_slot_mat_set(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float *mat, int size)
403 {
404         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
405         BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
406         if (!(slot->slot_type == BMO_OP_SLOT_MAT))
407                 return;
408
409         slot->len = 4;
410         slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
411         
412         if (size == 4) {
413                 copy_m4_m4(slot->data.p, (float (*)[4])mat);
414         }
415         else if (size == 3) {
416                 copy_m4_m3(slot->data.p, (float (*)[3])mat);
417         }
418         else {
419                 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
420
421                 zero_m4(slot->data.p);
422         }
423 }
424
425 void BMO_slot_mat4_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_mat[4][4])
426 {
427         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
428         BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
429         if (!(slot->slot_type == BMO_OP_SLOT_MAT))
430                 return;
431
432         if (slot->data.p) {
433                 copy_m4_m4(r_mat, BMO_SLOT_AS_MATRIX(slot));
434         }
435         else {
436                 unit_m4(r_mat);
437         }
438 }
439
440 void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_mat[3][3])
441 {
442         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
443         BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
444         if (!(slot->slot_type == BMO_OP_SLOT_MAT))
445                 return;
446
447         if (slot->data.p) {
448                 copy_m3_m4(r_mat, BMO_SLOT_AS_MATRIX(slot));
449         }
450         else {
451                 unit_m3(r_mat);
452         }
453 }
454
455 void BMO_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, void *p)
456 {
457         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
458         BLI_assert(slot->slot_type == BMO_OP_SLOT_PTR);
459         if (!(slot->slot_type == BMO_OP_SLOT_PTR))
460                 return;
461
462         slot->data.p = p;
463 }
464
465 void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float vec[3])
466 {
467         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
468         BLI_assert(slot->slot_type == BMO_OP_SLOT_VEC);
469         if (!(slot->slot_type == BMO_OP_SLOT_VEC))
470                 return;
471
472         copy_v3_v3(slot->data.vec, vec);
473 }
474
475
476 float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
477 {
478         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
479         BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
480         if (!(slot->slot_type == BMO_OP_SLOT_FLT))
481                 return 0.0f;
482
483         return slot->data.f;
484 }
485
486 int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
487 {
488         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
489         BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
490         if (!(slot->slot_type == BMO_OP_SLOT_INT))
491                 return 0;
492
493         return slot->data.i;
494 }
495
496 bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
497 {
498         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
499         BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
500         if (!(slot->slot_type == BMO_OP_SLOT_BOOL))
501                 return 0;
502
503         return slot->data.i;
504 }
505
506 /* if you want a copy of the elem buffer */
507 void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len)
508 {
509         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
510         void **ret;
511
512         /* could add support for mapping type */
513         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
514
515         ret = MEM_mallocN(sizeof(void *) * slot->len, __func__);
516         memcpy(ret, slot->data.buf, sizeof(void *) * slot->len);
517         *len = slot->len;
518         return ret;
519 }
520
521 void *BMO_slot_ptr_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
522 {
523         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
524         BLI_assert(slot->slot_type == BMO_OP_SLOT_PTR);
525         if (!(slot->slot_type == BMO_OP_SLOT_PTR))
526                 return NULL;
527
528         return slot->data.p;
529 }
530
531 void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3])
532 {
533         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
534         BLI_assert(slot->slot_type == BMO_OP_SLOT_VEC);
535         if (!(slot->slot_type == BMO_OP_SLOT_VEC))
536                 return;
537
538         copy_v3_v3(r_vec, slot->data.vec);
539 }
540
541 /*
542  * BMO_COUNTFLAG
543  *
544  * Counts the number of elements of a certain type that have a
545  * specific flag enabled (or disabled if test_for_enabled is false).
546  *
547  */
548
549 static int bmo_mesh_flag_count(BMesh *bm, const char htype, const short oflag,
550                                const bool test_for_enabled)
551 {
552         const char iter_types[3] = {BM_VERTS_OF_MESH,
553                                     BM_EDGES_OF_MESH,
554                                     BM_FACES_OF_MESH};
555
556         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
557
558         BMIter iter;
559         int count = 0;
560         BMElemF *ele_f;
561         int i;
562
563         for (i = 0; i < 3; i++) {
564                 if (htype & flag_types[i]) {
565                         BM_ITER_MESH (ele_f, &iter, bm, iter_types[i]) {
566                                 if (BMO_elem_flag_test_bool(bm, ele_f, oflag) == test_for_enabled)
567                                         count++;
568                         }
569                 }
570         }
571
572         return count;
573 }
574
575
576 int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag)
577 {
578         return bmo_mesh_flag_count(bm, htype, oflag, true);
579 }
580
581 int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag)
582 {
583         return bmo_mesh_flag_count(bm, htype, oflag, false);
584 }
585
586 void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
587 {
588         const char iter_types[3] = {BM_VERTS_OF_MESH,
589                                     BM_EDGES_OF_MESH,
590                                     BM_FACES_OF_MESH};
591
592         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
593
594         BMElemF *ele;
595         int i;
596
597 #pragma omp parallel for schedule(dynamic) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
598         for (i = 0; i < 3; i++) {
599                 if (htype & flag_types[i]) {
600                         BMIter iter;
601                         BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
602                                 BMO_elem_flag_disable(bm, ele, oflag);
603                         }
604                 }
605         }
606 }
607
608 void BMO_mesh_selected_remap(BMesh *bm,
609                              BMOpSlot *slot_vert_map,
610                              BMOpSlot *slot_edge_map,
611                              BMOpSlot *slot_face_map)
612 {
613         if (bm->selected.first) {
614                 BMEditSelection *ese, *ese_next;
615                 BMOpSlot *slot_elem_map;
616
617                 for (ese = bm->selected.first; ese; ese = ese_next) {
618                         ese_next = ese->next;
619
620                         switch (ese->htype) {
621                                 case BM_VERT: slot_elem_map = slot_vert_map; break;
622                                 case BM_EDGE: slot_elem_map = slot_edge_map; break;
623                                 default:      slot_elem_map = slot_face_map; break;
624                         }
625
626                         ese->ele = BMO_slot_map_elem_get(slot_elem_map, ese->ele);
627
628                         if (UNLIKELY((ese->ele == NULL) ||
629                                      (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT) == false)))
630                         {
631                                 BLI_remlink(&bm->selected, ese);
632                                 MEM_freeN(ese);
633                         }
634                 }
635         }
636
637         if (bm->act_face) {
638                 BMFace *f = BMO_slot_map_elem_get(slot_face_map, bm->act_face);
639                 if (f) {
640                         bm->act_face = f;
641                 }
642         }
643 }
644
645
646 int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
647 {
648         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
649         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
650         
651         /* check if its actually a buffer */
652         if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
653                 return 0;
654
655         return slot->len;
656 }
657
658 int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
659 {
660         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
661         BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
662         return BLI_ghash_size(slot->data.ghash);
663 }
664
665 /* inserts a key/value mapping into a mapping slot.  note that it copies the
666  * value, it doesn't store a reference to it. */
667
668 void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot,
669                          const void *element, const void *data)
670 {
671         (void) op;  /* Ignored in release builds. */
672
673         BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
674         BMO_ASSERT_SLOT_IN_OP(slot, op);
675
676         BLI_ghash_insert(slot->data.ghash, (void *)element, (void *)data);
677 }
678
679 #if 0
680 void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slot_code, int totadd)
681 {
682         BMOpSlot *slot = &op->slots[slot_code];
683         void *tmp;
684         ssize_t allocsize;
685         
686         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
687
688         /* check if its actually a buffer */
689         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
690                 return NULL;
691
692         if (slot->flag & BMOS_DYNAMIC_ARRAY) {
693                 if (slot->len >= slot->size) {
694                         slot->size = (slot->size + 1 + totadd) * 2;
695
696                         allocsize = BMO_OPSLOT_TYPEINFO[bmo_opdefines[op->type]->slot_types[slot_code].type] * slot->size;
697
698                         tmp = slot->data.buf;
699                         slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
700                         memcpy(slot->data.buf, tmp, allocsize);
701                         MEM_freeN(tmp);
702                 }
703
704                 slot->len += totadd;
705         }
706         else {
707                 slot->flag |= BMOS_DYNAMIC_ARRAY;
708                 slot->len += totadd;
709                 slot->size = slot->len + 2;
710
711                 allocsize = BMO_OPSLOT_TYPEINFO[bmo_opdefines[op->type]->slot_types[slot_code].type] * slot->len;
712
713                 tmp = slot->data.buf;
714                 slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
715                 memcpy(slot->data.buf, tmp, allocsize);
716         }
717
718         return slot->data.buf;
719 }
720 #endif
721
722 void BMO_slot_map_to_flag(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
723                           const char htype, const short oflag)
724 {
725         GHashIterator it;
726         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
727         BMElemF *ele_f;
728
729         BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
730
731
732         for (BLI_ghashIterator_init(&it, slot->data.ghash);
733              (ele_f = BLI_ghashIterator_getKey(&it));
734              BLI_ghashIterator_step(&it))
735         {
736                 if (ele_f->head.htype & htype) {
737                         BMO_elem_flag_enable(bm, ele_f, oflag);
738                 }
739         }
740 }
741
742 void *BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int len)
743 {
744         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
745
746         /* check if its actually a buffer */
747         if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
748                 return NULL;
749         
750         slot->len = len;
751         if (len) {
752                 slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slot_type] * len);
753         }
754         else {
755                 slot->data.buf = NULL;
756         }
757
758         return slot->data.buf;
759 }
760
761 /**
762  * \brief BMO_ALL_TO_SLOT
763  *
764  * Copies all elements of a certain type into an operator slot.
765  */
766 void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
767                               const char *slot_name, const char htype)
768 {
769         BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
770         int totelement = 0, i = 0;
771         
772         if (htype & BM_VERT) totelement += bm->totvert;
773         if (htype & BM_EDGE) totelement += bm->totedge;
774         if (htype & BM_FACE) totelement += bm->totface;
775
776         if (totelement) {
777                 BMIter iter;
778                 BMHeader *ele;
779
780                 BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
781
782                 /* TODO - collapse these loops into one */
783
784                 if (htype & BM_VERT) {
785                         BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
786                                 output->data.buf[i] = ele;
787                                 i++;
788                         }
789                 }
790
791                 if (htype & BM_EDGE) {
792                         BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
793                                 output->data.buf[i] = ele;
794                                 i++;
795                         }
796                 }
797
798                 if (htype & BM_FACE) {
799                         BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
800                                 output->data.buf[i] = ele;
801                                 i++;
802                         }
803                 }
804         }
805 }
806
807 /**
808  * \brief BMO_HEADERFLAG_TO_SLOT
809  *
810  * Copies elements of a certain type, which have a certain header flag
811  * enabled/disabled into a slot for an operator.
812  */
813 static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
814                                        const char htype, const char hflag,
815                                        const bool test_for_enabled)
816 {
817         BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
818         int totelement = 0, i = 0;
819         const int respecthide = (op->flag & BMO_FLAG_RESPECT_HIDE) != 0;
820
821         if (test_for_enabled)
822                 totelement = BM_mesh_elem_hflag_count_enabled(bm, htype, hflag, respecthide);
823         else
824                 totelement = BM_mesh_elem_hflag_count_disabled(bm, htype, hflag, respecthide);
825
826         if (totelement) {
827                 BMIter iter;
828                 BMElem *ele;
829
830                 BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
831
832                 /* TODO - collapse these loops into one */
833
834                 if (htype & BM_VERT) {
835                         BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
836                                 if ((!respecthide || !BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) &&
837                                     BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
838                                 {
839                                         output->data.buf[i] = ele;
840                                         i++;
841                                 }
842                         }
843                 }
844
845                 if (htype & BM_EDGE) {
846                         BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
847                                 if ((!respecthide || !BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) &&
848                                     BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
849                                 {
850                                         output->data.buf[i] = ele;
851                                         i++;
852                                 }
853                         }
854                 }
855
856                 if (htype & BM_FACE) {
857                         BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
858                                 if ((!respecthide || !BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) &&
859                                     BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
860                                 {
861                                         output->data.buf[i] = ele;
862                                         i++;
863                                 }
864                         }
865                 }
866         }
867         else {
868                 output->len = 0;
869         }
870 }
871
872 void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op,
873                                         BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
874                                         const char htype, const char hflag)
875 {
876         bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, true);
877 }
878
879 void BMO_slot_buffer_from_disabled_hflag(BMesh *bm, BMOperator *op,
880                                          BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
881                                          const char htype, const char hflag)
882 {
883         bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, false);
884 }
885
886 void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele)
887 {
888         BMO_ASSERT_SLOT_IN_OP(slot, op);
889         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
890         BLI_assert(slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE);
891         BLI_assert(slot->len == 0 || slot->len == 1);
892
893         BLI_assert(slot->slot_subtype.elem & ele->htype);
894
895         slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);  /* XXX, why 'x4' ? */
896         slot->len = 1;
897         *slot->data.buf = ele;
898 }
899
900 void *BMO_slot_buffer_get_single(BMOpSlot *slot)
901 {
902         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
903         BLI_assert(slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE);
904         BLI_assert(slot->len == 0 || slot->len == 1);
905
906         return slot->len ? (BMHeader *)slot->data.buf[0] : NULL;
907 }
908
909 /**
910  * Copies the values from another slot to the end of the output slot.
911  */
912 void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
913                              BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
914                              struct MemArena *arena_dst)
915 {
916         BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
917         BMOpSlot *slot_src  = BMO_slot_get(slot_args_src,  slot_name_src);
918
919         BLI_assert(slot_dst->slot_type == BMO_OP_SLOT_ELEMENT_BUF &&
920                    slot_src->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
921
922         if (slot_dst->len == 0) {
923                 /* output slot is empty, copy rather than append */
924                 _bmo_slot_copy(slot_args_src, slot_name_src,
925                                slot_args_dst, slot_name_dst,
926                                arena_dst);
927         }
928         else if (slot_src->len != 0) {
929                 int elem_size = BMO_OPSLOT_TYPEINFO[slot_dst->slot_type];
930                 int alloc_size = elem_size * (slot_dst->len + slot_src->len);
931                 /* allocate new buffer */
932                 void *buf = BLI_memarena_alloc(arena_dst, alloc_size);
933
934                 /* copy slot data */
935                 memcpy(buf, slot_dst->data.buf, elem_size * slot_dst->len);
936                 memcpy(((char *)buf) + elem_size * slot_dst->len, slot_src->data.buf, elem_size * slot_src->len);
937
938                 slot_dst->data.buf = buf;
939                 slot_dst->len += slot_src->len;
940         }
941 }
942
943 /**
944  * \brief BMO_FLAG_TO_SLOT
945  *
946  * Copies elements of a certain type, which have a certain flag set
947  * into an output slot for an operator.
948  */
949 static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op,
950                                       BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
951                                       const char htype, const short oflag,
952                                       const bool test_for_enabled)
953 {
954         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
955         int totelement, i = 0;
956
957         BLI_assert(op->slots_in == slot_args || op->slots_out == slot_args);
958
959         if (test_for_enabled)
960                 totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag);
961         else
962                 totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag);
963
964         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
965         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
966
967         if (totelement) {
968                 BMIter iter;
969                 BMHeader *ele;
970                 BMHeader **ele_array;
971
972                 BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
973
974                 ele_array = (BMHeader **)slot->data.buf;
975
976                 /* TODO - collapse these loops into one */
977
978                 if (htype & BM_VERT) {
979                         BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
980                                 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
981                                         ele_array[i] = ele;
982                                         i++;
983                                 }
984                         }
985                 }
986
987                 if (htype & BM_EDGE) {
988                         BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
989                                 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
990                                         ele_array[i] = ele;
991                                         i++;
992                                 }
993                         }
994                 }
995
996                 if (htype & BM_FACE) {
997                         BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
998                                 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
999                                         ele_array[i] = ele;
1000                                         i++;
1001                                 }
1002                         }
1003                 }
1004         }
1005         else {
1006                 slot->len = 0;
1007         }
1008 }
1009
1010 void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op,
1011                                        BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1012                                        const char htype, const short oflag)
1013 {
1014         bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, true);
1015 }
1016
1017 void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op,
1018                                         BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1019                                         const char htype, const short oflag)
1020 {
1021         bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, false);
1022 }
1023
1024 /**
1025  * \brief BMO_FLAG_BUFFER
1026  *
1027  * Header Flags elements in a slots buffer, automatically
1028  * using the selection API where appropriate.
1029  */
1030 void BMO_slot_buffer_hflag_enable(BMesh *bm,
1031                                   BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1032                                   const char htype, const char hflag, const bool do_flush)
1033 {
1034         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1035         BMElem **data =  (BMElem **)slot->data.buf;
1036         int i;
1037         const bool do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
1038         const bool do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
1039
1040         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1041         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1042
1043         for (i = 0; i < slot->len; i++, data++) {
1044                 if (!(htype & (*data)->head.htype))
1045                         continue;
1046
1047                 if (do_flush_select) {
1048                         BM_elem_select_set(bm, *data, true);
1049                 }
1050
1051                 if (do_flush_hide) {
1052                         BM_elem_hide_set(bm, *data, false);
1053                 }
1054
1055                 BM_elem_flag_enable(*data, hflag);
1056         }
1057 }
1058
1059 /**
1060  * \brief BMO_FLAG_BUFFER
1061  *
1062  * Removes flags from elements in a slots buffer, automatically
1063  * using the selection API where appropriate.
1064  */
1065 void BMO_slot_buffer_hflag_disable(BMesh *bm,
1066                                    BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1067                                    const char htype, const char hflag, const bool do_flush)
1068 {
1069         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1070         BMElem **data =  (BMElem **)slot->data.buf;
1071         int i;
1072         const bool do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
1073         const bool do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
1074
1075         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1076         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1077
1078         for (i = 0; i < slot->len; i++, data++) {
1079                 if (!(htype & (*data)->head.htype))
1080                         continue;
1081
1082                 if (do_flush_select) {
1083                         BM_elem_select_set(bm, *data, false);
1084                 }
1085
1086                 if (do_flush_hide) {
1087                         BM_elem_hide_set(bm, *data, false);
1088                 }
1089
1090                 BM_elem_flag_disable(*data, hflag);
1091         }
1092 }
1093
1094 /**
1095  * \brief BMO_FLAG_BUFFER
1096  *
1097  * Flags elements in a slots buffer
1098  */
1099 void BMO_slot_buffer_flag_enable(BMesh *bm,
1100                                  BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1101                                  const char htype, const short oflag)
1102 {
1103         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1104         BMHeader **data =  slot->data.p;
1105         int i;
1106
1107         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1108         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1109
1110         for (i = 0; i < slot->len; i++) {
1111                 if (!(htype & data[i]->htype))
1112                         continue;
1113
1114                 BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
1115         }
1116 }
1117
1118 /**
1119  * \brief BMO_FLAG_BUFFER
1120  *
1121  * Removes flags from elements in a slots buffer
1122  */
1123 void BMO_slot_buffer_flag_disable(BMesh *bm,
1124                                   BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1125                                   const char htype, const short oflag)
1126 {
1127         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1128         BMHeader **data = (BMHeader **)slot->data.buf;
1129         int i;
1130
1131         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1132         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1133
1134         for (i = 0; i < slot->len; i++) {
1135                 if (!(htype & data[i]->htype))
1136                         continue;
1137
1138                 BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
1139         }
1140 }
1141
1142
1143 /**
1144  * \brief ALLOC/FREE FLAG LAYER
1145  *
1146  * Used by operator stack to free/allocate
1147  * private flag data. This is allocated
1148  * using a mempool so the allocation/frees
1149  * should be quite fast.
1150  *
1151  * BMESH_TODO:
1152  * Investigate not freeing flag layers until
1153  * all operators have been executed. This would
1154  * save a lot of realloc potentially.
1155  */
1156 static void bmo_flag_layer_alloc(BMesh *bm)
1157 {
1158         /* set the index values since we are looping over all data anyway,
1159          * may save time later on */
1160
1161         BLI_mempool *voldpool = bm->vtoolflagpool;  /* old flag pool */
1162         BLI_mempool *eoldpool = bm->etoolflagpool;  /* old flag pool */
1163         BLI_mempool *foldpool = bm->ftoolflagpool;  /* old flag pool */
1164
1165         /* store memcpy size for reuse */
1166         const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
1167
1168         bm->totflags++;
1169
1170         bm->vtoolflagpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, bm->totvert, 512, BLI_MEMPOOL_NOP);
1171         bm->etoolflagpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, bm->totedge, 512, BLI_MEMPOOL_NOP);
1172         bm->ftoolflagpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, bm->totface, 512, BLI_MEMPOOL_NOP);
1173
1174 #pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
1175         {
1176 #pragma omp section
1177                 {
1178                         BMIter iter;
1179                         BMElemF *ele;
1180                         int i;
1181
1182                         BLI_mempool *newpool = bm->vtoolflagpool;
1183
1184                         /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
1185                         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1186                                 void *oldflags = ele->oflags;
1187                                 ele->oflags = BLI_mempool_calloc(newpool);
1188                                 memcpy(ele->oflags, oldflags, old_totflags_size);
1189                                 BM_elem_index_set(ele, i); /* set_inline */
1190                                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1191                         }
1192                 }
1193 #pragma omp section
1194                 {
1195                         BMIter iter;
1196                         BMElemF *ele;
1197                         int i;
1198
1199                         BLI_mempool *newpool = bm->etoolflagpool;
1200
1201                         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1202                                 void *oldflags = ele->oflags;
1203                                 ele->oflags = BLI_mempool_calloc(newpool);
1204                                 memcpy(ele->oflags, oldflags, old_totflags_size);
1205                                 BM_elem_index_set(ele, i); /* set_inline */
1206                                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1207                         }
1208                 }
1209 #pragma omp section
1210                 {
1211                         BMIter iter;
1212                         BMElemF *ele;
1213                         int i;
1214
1215                         BLI_mempool *newpool = bm->ftoolflagpool;
1216
1217                         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1218                                 void *oldflags = ele->oflags;
1219                                 ele->oflags = BLI_mempool_calloc(newpool);
1220                                 memcpy(ele->oflags, oldflags, old_totflags_size);
1221                                 BM_elem_index_set(ele, i); /* set_inline */
1222                                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1223                         }
1224                 }
1225         }
1226
1227         BLI_mempool_destroy(voldpool);
1228         BLI_mempool_destroy(eoldpool);
1229         BLI_mempool_destroy(foldpool);
1230
1231         bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1232
1233
1234 }
1235
1236 static void bmo_flag_layer_free(BMesh *bm)
1237 {
1238         /* set the index values since we are looping over all data anyway,
1239          * may save time later on */
1240
1241         BLI_mempool *voldpool = bm->vtoolflagpool;
1242         BLI_mempool *eoldpool = bm->etoolflagpool;
1243         BLI_mempool *foldpool = bm->ftoolflagpool;
1244
1245         /* store memcpy size for reuse */
1246         const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
1247
1248         /* de-increment the totflags first.. */
1249         bm->totflags--;
1250
1251         bm->vtoolflagpool = BLI_mempool_create(new_totflags_size, bm->totvert, 512, BLI_MEMPOOL_NOP);
1252         bm->etoolflagpool = BLI_mempool_create(new_totflags_size, bm->totedge, 512, BLI_MEMPOOL_NOP);
1253         bm->ftoolflagpool = BLI_mempool_create(new_totflags_size, bm->totface, 512, BLI_MEMPOOL_NOP);
1254
1255 #pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
1256         {
1257 #pragma omp section
1258                 {
1259                         BMIter iter;
1260                         BMElemF *ele;
1261                         int i;
1262
1263                         BLI_mempool *newpool = bm->vtoolflagpool;
1264
1265                         /* now go through and memcpy all the flag */
1266                         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1267                                 void *oldflags = ele->oflags;
1268                                 ele->oflags = BLI_mempool_alloc(newpool);
1269                                 memcpy(ele->oflags, oldflags, new_totflags_size);
1270                                 BM_elem_index_set(ele, i); /* set_inline */
1271                                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1272                         }
1273                 }
1274 #pragma omp section
1275                 {
1276                         BMIter iter;
1277                         BMElemF *ele;
1278                         int i;
1279
1280                         BLI_mempool *newpool = bm->etoolflagpool;
1281
1282                         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1283                                 void *oldflags = ele->oflags;
1284                                 ele->oflags = BLI_mempool_alloc(newpool);
1285                                 memcpy(ele->oflags, oldflags, new_totflags_size);
1286                                 BM_elem_index_set(ele, i); /* set_inline */
1287                                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1288                         }
1289                 }
1290 #pragma omp section
1291                 {
1292                         BMIter iter;
1293                         BMElemF *ele;
1294                         int i;
1295
1296                         BLI_mempool *newpool = bm->ftoolflagpool;
1297
1298                         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1299                                 void *oldflags = ele->oflags;
1300                                 ele->oflags = BLI_mempool_alloc(newpool);
1301                                 memcpy(ele->oflags, oldflags, new_totflags_size);
1302                                 BM_elem_index_set(ele, i); /* set_inline */
1303                                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1304                         }
1305                 }
1306         }
1307
1308         BLI_mempool_destroy(voldpool);
1309         BLI_mempool_destroy(eoldpool);
1310         BLI_mempool_destroy(foldpool);
1311
1312         bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1313 }
1314
1315 static void bmo_flag_layer_clear(BMesh *bm)
1316 {
1317         /* set the index values since we are looping over all data anyway,
1318          * may save time later on */
1319         const BMFlagLayer zero_flag = {0};
1320
1321         const int totflags_offset = bm->totflags - 1;
1322
1323 #pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
1324         {
1325                 /* now go through and memcpy all the flag */
1326 #pragma omp section
1327                 {
1328                         BMIter iter;
1329                         BMElemF *ele;
1330                         int i;
1331                         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1332                                 ele->oflags[totflags_offset] = zero_flag;
1333                                 BM_elem_index_set(ele, i); /* set_inline */
1334                         }
1335                 }
1336 #pragma omp section
1337                 {
1338                         BMIter iter;
1339                         BMElemF *ele;
1340                         int i;
1341                         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1342                                 ele->oflags[totflags_offset] = zero_flag;
1343                                 BM_elem_index_set(ele, i); /* set_inline */
1344                         }
1345                 }
1346 #pragma omp section
1347                 {
1348                         BMIter iter;
1349                         BMElemF *ele;
1350                         int i;
1351                         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1352                                 ele->oflags[totflags_offset] = zero_flag;
1353                                 BM_elem_index_set(ele, i); /* set_inline */
1354                         }
1355                 }
1356         }
1357
1358         bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1359 }
1360
1361 void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
1362 {
1363         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1364         
1365         if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
1366                 return NULL;
1367
1368         return slot->data.buf ? *slot->data.buf : NULL;
1369 }
1370
1371 /**
1372  * \brief New Iterator
1373  *
1374  * \param restrictmask restricts the iteration to certain element types
1375  * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
1376  * over an element buffer (not a mapping). */
1377 void *BMO_iter_new(BMOIter *iter,
1378                    BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1379                    const char restrictmask)
1380 {
1381         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1382
1383         memset(iter, 0, sizeof(BMOIter));
1384
1385         iter->slot = slot;
1386         iter->cur = 0;
1387         iter->restrictmask = restrictmask;
1388
1389         if (iter->slot->slot_type == BMO_OP_SLOT_MAPPING) {
1390                 BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1391         }
1392         else if (iter->slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
1393                 BLI_assert(restrictmask & slot->slot_subtype.elem);
1394         }
1395         else {
1396                 BLI_assert(0);
1397         }
1398
1399         return BMO_iter_step(iter);
1400 }
1401
1402 void *BMO_iter_step(BMOIter *iter)
1403 {
1404         BMOpSlot *slot = iter->slot;
1405         if (slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
1406                 BMHeader *ele;
1407
1408                 if (iter->cur >= slot->len) {
1409                         return NULL;
1410                 }
1411
1412                 ele = slot->data.buf[iter->cur++];
1413                 while (!(iter->restrictmask & ele->htype)) {
1414                         if (iter->cur >= slot->len) {
1415                                 return NULL;
1416                         }
1417
1418                         ele = slot->data.buf[iter->cur++];
1419                         BLI_assert((ele == NULL) || (slot->slot_subtype.elem & ele->htype));
1420                 }
1421
1422                 BLI_assert((ele == NULL) || (slot->slot_subtype.elem & ele->htype));
1423
1424                 return ele;
1425         }
1426         else if (slot->slot_type == BMO_OP_SLOT_MAPPING) {
1427                 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1428                 iter->val = BLI_ghashIterator_getValue_p(&iter->giter);
1429
1430                 BLI_ghashIterator_step(&iter->giter);
1431
1432                 return ret;
1433         }
1434         else {
1435                 BLI_assert(0);
1436         }
1437
1438         return NULL;
1439 }
1440
1441 /* used for iterating over mappings */
1442
1443 /**
1444  * Returns a pointer to the key-value when iterating over mappings.
1445  * remember for pointer maps this will be a pointer to a pointer.
1446  */
1447 void **BMO_iter_map_value_p(BMOIter *iter)
1448 {
1449         return iter->val;
1450 }
1451
1452 void *BMO_iter_map_value_ptr(BMOIter *iter)
1453 {
1454         BLI_assert(ELEM(iter->slot->slot_subtype.map,
1455                         BMO_OP_SLOT_SUBTYPE_MAP_ELEM, BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL));
1456         return iter->val ? *iter->val : NULL;
1457 }
1458
1459
1460 float BMO_iter_map_value_float(BMOIter *iter)
1461 {
1462         BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_FLT);
1463         return **((float **)iter->val);
1464 }
1465
1466 int BMO_iter_map_value_int(BMOIter *iter)
1467 {
1468         BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INT);
1469         return **((int **)iter->val);
1470 }
1471
1472 bool BMO_iter_map_value_bool(BMOIter *iter)
1473 {
1474         BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_BOOL);
1475         return **((bool **)iter->val);
1476 }
1477
1478 /* error system */
1479 typedef struct BMOpError {
1480         struct BMOpError *next, *prev;
1481         int errorcode;
1482         BMOperator *op;
1483         const char *msg;
1484 } BMOpError;
1485
1486 void BMO_error_clear(BMesh *bm)
1487 {
1488         while (BMO_error_pop(bm, NULL, NULL));
1489 }
1490
1491 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1492 {
1493         BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1494         
1495         err->errorcode = errcode;
1496         if (!msg) {
1497                 msg = bmo_error_messages[errcode];
1498         }
1499         err->msg = msg;
1500         err->op = owner;
1501         
1502         BLI_addhead(&bm->errorstack, err);
1503 }
1504
1505 bool BMO_error_occurred(BMesh *bm)
1506 {
1507         return (BLI_listbase_is_empty(&bm->errorstack) == false);
1508 }
1509
1510 /* returns error code or 0 if no error */
1511 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1512 {
1513         BMOpError *err = bm->errorstack.first;
1514         if (!err) {
1515                 return 0;
1516         }
1517
1518         if (msg) *msg = err->msg;
1519         if (op) *op = err->op;
1520         
1521         return err->errorcode;
1522 }
1523
1524 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1525 {
1526         int errorcode = BMO_error_get(bm, msg, op);
1527         
1528         if (errorcode) {
1529                 BMOpError *err = bm->errorstack.first;
1530                 
1531                 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1532                 MEM_freeN(err);
1533         }
1534
1535         return errorcode;
1536 }
1537
1538
1539 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1540
1541 static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
1542 {
1543         int i = 0;
1544
1545         while (slot_args->slot_name) {
1546                 if (STREQLEN(identifier, slot_args->slot_name, MAX_SLOTNAME)) {
1547                         return i;
1548                 }
1549                 slot_args++;
1550                 i++;
1551         }
1552
1553         return -1;
1554 }
1555
1556 static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
1557 {
1558         int i = bmo_name_to_slotcode(slot_args, identifier);
1559         if (i < 0) {
1560                 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, identifier);
1561         }
1562
1563         return i;
1564 }
1565
1566 int BMO_opcode_from_opname(const char *opname)
1567 {
1568
1569         const unsigned int tot = bmo_opdefines_total;
1570         unsigned int i;
1571         for (i = 0; i < tot; i++) {
1572                 if (STREQ(bmo_opdefines[i]->opname, opname)) {
1573                         return i;
1574                 }
1575         }
1576         return -1;
1577 }
1578
1579 static int BMO_opcode_from_opname_check(const char *opname)
1580 {
1581         int i = BMO_opcode_from_opname(opname);
1582         if (i == -1)
1583                 fprintf(stderr, "%s: could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1584         return i;
1585 }
1586
1587 /**
1588  * \brief Format Strings for #BMOperator Initialization.
1589  *
1590  * This system is used to execute or initialize an operator,
1591  * using a formatted-string system.
1592  *
1593  * The basic format for the format string is:
1594  * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
1595  *
1596  * Example:
1597  *
1598  * \code{.c}
1599  *     BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
1600  *                  "delete context=%i geom=%hv",
1601  *                  DEL_ONLYFACES, BM_ELEM_SELECT);
1602  * \endcode
1603  *
1604  *
1605  * **Primitive Types**
1606  * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
1607  * - `i` - int. #BMO_OP_SLOT_INT
1608  * - `f` - float. #BMO_OP_SLOT_FLT
1609  * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
1610  * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
1611  * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
1612  * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
1613  *
1614  *
1615  * **Utility**
1616  *
1617  * Pass an existing slot which is copied to either an input or output slot.
1618  * Taking the operator and slot-name pair of args (BMOperator *, const char *).
1619  * - `s` - slot_in (lower case)
1620  * - `S` - slot_out (upper case)
1621  *
1622  *
1623  * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
1624  * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
1625  * - `av` - all verts
1626  * - `ae` - all edges
1627  * - `af` - all faces
1628  * - `hv` - header flagged verts (hflag)
1629  * - `he` - header flagged edges (hflag)
1630  * - `hf` - header flagged faces (hflag)
1631  * - `Hv` - header flagged verts (hflag off)
1632  * - `He` - header flagged edges (hflag off)
1633  * - `Hf` - header flagged faces (hflag off)
1634  * - `fv` - flagged verts (oflag)
1635  * - `fe` - flagged edges (oflag)
1636  * - `ff` - flagged faces (oflag)
1637  * - `Fv` - flagged verts (oflag off)
1638  * - `Fe` - flagged edges (oflag off)
1639  * - `Ff` - flagged faces (oflag off)
1640  *
1641  * \note The common v/e/f suffix can be mixed,
1642  * so `avef` is can be used for all verts, edges and faces.
1643  * Order is not important so `Hfev` is also valid (all unflagged verts, edges and faces).
1644  */
1645
1646 bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, va_list vlist)
1647 {
1648 //      BMOpDefine *def;
1649         char *opname, *ofmt, *fmt;
1650         char slot_name[64] = {0};
1651         int i, type;
1652         bool noslot, state;
1653         char htype;
1654
1655
1656         /* basic useful info to help find where bmop formatting strings fail */
1657         const char *err_reason = "Unknown";
1658         int lineno = -1;
1659
1660 #define GOTO_ERROR(reason)   \
1661         {                        \
1662                 err_reason = reason; \
1663                 lineno = __LINE__;   \
1664                 goto error;          \
1665         } (void)0
1666
1667         /* we muck around in here, so dup it */
1668         fmt = ofmt = BLI_strdup(_fmt);
1669         
1670         /* find operator name */
1671         i = strcspn(fmt, " ");
1672
1673         opname = fmt;
1674         noslot = (opname[i] == '\0');
1675         opname[i] = '\0';
1676
1677         fmt += i + (noslot ? 0 : 1);
1678         
1679         i = BMO_opcode_from_opname_check(opname);
1680
1681         if (i == -1) {
1682                 MEM_freeN(ofmt);
1683                 BLI_assert(0);
1684                 return false;
1685         }
1686
1687         BMO_op_init(bm, op, flag, opname);
1688 //      def = bmo_opdefines[i];
1689         
1690         i = 0;
1691         state = true;  /* false: not inside slot_code name, true: inside slot_code name */
1692
1693         while (*fmt) {
1694                 if (state) {
1695                         /* jump past leading whitespace */
1696                         i = strspn(fmt, " ");
1697                         fmt += i;
1698                         
1699                         /* ignore trailing whitespace */
1700                         if (!fmt[i])
1701                                 break;
1702
1703                         /* find end of slot name, only "slot=%f", can be used */
1704                         i = strcspn(fmt, "=");
1705                         if (!fmt[i]) {
1706                                 GOTO_ERROR("could not match end of slot name");
1707                         }
1708
1709                         fmt[i] = 0;
1710
1711                         if (bmo_name_to_slotcode_check(op->slots_in, fmt) < 0) {
1712                                 GOTO_ERROR("name to slot code check failed");
1713                         }
1714                         
1715                         BLI_strncpy(slot_name, fmt, sizeof(slot_name));
1716                         
1717                         state = false;
1718                         fmt += i;
1719                 }
1720                 else {
1721                         switch (*fmt) {
1722                                 case ' ':
1723                                 case '=':
1724                                 case '%':
1725                                         break;
1726                                 case 'm':
1727                                 {
1728                                         int size, c;
1729
1730                                         c = NEXT_CHAR(fmt);
1731                                         fmt++;
1732
1733                                         if      (c == '3') size = 3;
1734                                         else if (c == '4') size = 4;
1735                                         else GOTO_ERROR("matrix size was not 3 or 4");
1736
1737                                         BMO_slot_mat_set(op, op->slots_in, slot_name, va_arg(vlist, void *), size);
1738                                         state = true;
1739                                         break;
1740                                 }
1741                                 case 'v':
1742                                 {
1743                                         BMO_slot_vec_set(op->slots_in, slot_name, va_arg(vlist, float *));
1744                                         state = true;
1745                                         break;
1746                                 }
1747                                 case 'e':  /* single vert/edge/face */
1748                                 {
1749                                         BMHeader *ele = va_arg(vlist, void *);
1750                                         BMOpSlot *slot = BMO_slot_get(op->slots_in, slot_name);
1751
1752                                         BMO_slot_buffer_from_single(op, slot, ele);
1753
1754                                         state = true;
1755                                         break;
1756                                 }
1757                                 case 's':
1758                                 case 'S':
1759                                 {
1760                                         BMOperator *op_other        = va_arg(vlist, void *);
1761                                         const char *slot_name_other = va_arg(vlist, char *);
1762
1763                                         if (*fmt == 's') {
1764                                                 BLI_assert(bmo_name_to_slotcode_check(op_other->slots_in, slot_name_other) != -1);
1765                                                 BMO_slot_copy(op_other, slots_in, slot_name_other,
1766                                                               op,       slots_in, slot_name);
1767                                         }
1768                                         else {
1769                                                 BLI_assert(bmo_name_to_slotcode_check(op_other->slots_out, slot_name_other) != -1);
1770                                                 BMO_slot_copy(op_other, slots_out, slot_name_other,
1771                                                               op,       slots_in, slot_name);
1772                                         }
1773                                         state = true;
1774                                         break;
1775                                 }
1776                                 case 'i':
1777                                         BMO_slot_int_set(op->slots_in, slot_name, va_arg(vlist, int));
1778                                         state = true;
1779                                         break;
1780                                 case 'b':
1781                                         BMO_slot_bool_set(op->slots_in, slot_name, va_arg(vlist, int));
1782                                         state = true;
1783                                         break;
1784                                 case 'p':
1785                                         BMO_slot_ptr_set(op->slots_in, slot_name, va_arg(vlist, void *));
1786                                         state = true;
1787                                         break;
1788                                 case 'f':
1789                                 case 'F':
1790                                 case 'h':
1791                                 case 'H':
1792                                 case 'a':
1793                                         type = *fmt;
1794
1795                                         if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\0') {
1796                                                 BMO_slot_float_set(op->slots_in, slot_name, va_arg(vlist, double));
1797                                         }
1798                                         else {
1799                                                 bool stop = false;
1800
1801                                                 htype = 0;
1802                                                 while (1) {
1803                                                         switch (NEXT_CHAR(fmt)) {
1804                                                                 case 'f': htype |= BM_FACE; break;
1805                                                                 case 'e': htype |= BM_EDGE; break;
1806                                                                 case 'v': htype |= BM_VERT; break;
1807                                                                 default:
1808                                                                         stop = true;
1809                                                                         break;
1810                                                         }
1811                                                         if (stop) {
1812                                                                 break;
1813                                                         }
1814
1815                                                         fmt++;
1816                                                 }
1817
1818                                                 if (type == 'h') {
1819                                                         BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1820                                                 }
1821                                                 else if (type == 'H') {
1822                                                         BMO_slot_buffer_from_disabled_hflag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1823                                                 }
1824                                                 else if (type == 'a') {
1825                                                         BMO_slot_buffer_from_all(bm, op, op->slots_in, slot_name, htype);
1826                                                 }
1827                                                 else if (type == 'f') {
1828                                                         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1829                                                 }
1830                                                 else if (type == 'F') {
1831                                                         BMO_slot_buffer_from_disabled_flag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1832                                                 }
1833                                         }
1834
1835                                         state = true;
1836                                         break;
1837                                 default:
1838                                         fprintf(stderr,
1839                                                 "%s: unrecognized bmop format char: '%c', %d in '%s'\n",
1840                                                 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1841                                         break;
1842                         }
1843                 }
1844                 fmt++;
1845         }
1846
1847         MEM_freeN(ofmt);
1848         return true;
1849 error:
1850
1851         /* non urgent todo - explain exactly what is failing */
1852         fprintf(stderr, "%s: error parsing formatting string\n", __func__);
1853
1854         fprintf(stderr, "string: '%s', position %d\n", _fmt, (int)(fmt - ofmt));
1855         fprintf(stderr, "         ");
1856         {
1857                 int pos = (int)(fmt - ofmt);
1858                 int i;
1859                 for (i = 0; i < pos; i++) {
1860                         fprintf(stderr, " ");
1861                 }
1862                 fprintf(stderr, "^\n");
1863         }
1864
1865         fprintf(stderr, "source code:  %s:%d\n", __FILE__, lineno);
1866
1867         fprintf(stderr, "reason: %s\n", err_reason);
1868
1869
1870         MEM_freeN(ofmt);
1871
1872         BMO_op_finish(bm, op);
1873         return false;
1874
1875 #undef GOTO_ERROR
1876
1877 }
1878
1879
1880 bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, ...)
1881 {
1882         va_list list;
1883
1884         va_start(list, fmt);
1885         if (!BMO_op_vinitf(bm, op, flag, fmt, list)) {
1886                 printf("%s: failed\n", __func__);
1887                 va_end(list);
1888                 return false;
1889         }
1890         va_end(list);
1891
1892         return true;
1893 }
1894
1895 bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt, ...)
1896 {
1897         va_list list;
1898         BMOperator op;
1899
1900         va_start(list, fmt);
1901         if (!BMO_op_vinitf(bm, &op, flag, fmt, list)) {
1902                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1903                 va_end(list);
1904                 return false;
1905         }
1906
1907         BMO_op_exec(bm, &op);
1908         BMO_op_finish(bm, &op);
1909
1910         va_end(list);
1911         return true;
1912 }