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