Speedup for ngon normal calculation
[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 #include "BLI_array.h"
38
39 #include "bmesh.h"
40 #include "intern/bmesh_private.h"
41
42 /* forward declarations */
43 static void bmo_flag_layer_alloc(BMesh *bm);
44 static void bmo_flag_layer_free(BMesh *bm);
45 static void bmo_flag_layer_clear(BMesh *bm);
46 static int bmo_name_to_slotcode(BMOpDefine *def, const char *name);
47 static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name);
48 static int bmo_opname_to_opcode(const char *opname);
49
50 static const char *bmo_error_messages[] = {
51         NULL,
52         "Self intersection error",
53         "Could not dissolve vert",
54         "Could not connect vertices",
55         "Could not traverse mesh",
56         "Could not dissolve faces",
57         "Could not dissolve vertices",
58         "Tessellation error",
59         "Can not deal with non-manifold geometry",
60         "Invalid selection",
61         "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,
68         sizeof(int),
69         sizeof(int),
70         sizeof(float),
71         sizeof(void *),
72         0, /* unused */
73         0, /* unused */
74         0, /* unused */
75         sizeof(void *), /* pointer buffer */
76         sizeof(BMOElemMapping)
77 };
78
79 /* Dummy slot so there is something to return when slot name lookup fails */
80 static BMOpSlot BMOpEmptySlot = {0};
81
82 void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
83 {
84         op->flag |= op_flag;
85 }
86
87 void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
88 {
89         op->flag &= ~op_flag;
90 }
91
92 /**
93  * \brief BMESH OPSTACK PUSH
94  *
95  * Pushes the opstack down one level and allocates a new flag layer if appropriate.
96  */
97 void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
98 {
99         bm->stackdepth++;
100
101         /* add flag layer, if appropriate */
102         if (bm->stackdepth > 1)
103                 bmo_flag_layer_alloc(bm);
104         else
105                 bmo_flag_layer_clear(bm);
106 }
107
108 /**
109  * \brief BMESH OPSTACK POP
110  *
111  * Pops the opstack one level and frees a flag layer if appropriate
112  *
113  * BMESH_TODO: investigate NOT freeing flag layers.
114  */
115 void BMO_pop(BMesh *bm)
116 {
117         if (bm->stackdepth > 1)
118                 bmo_flag_layer_free(bm);
119
120         bm->stackdepth--;
121 }
122
123 /**
124  * \brief BMESH OPSTACK INIT OP
125  *
126  * Initializes an operator structure to a certain type
127  */
128 void BMO_op_init(BMesh *bm, BMOperator *op, const char *opname)
129 {
130         int i, opcode = bmo_opname_to_opcode(opname);
131
132 #ifdef DEBUG
133         BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
134 #else
135         (void)bm;
136 #endif
137
138         if (opcode == -1) {
139                 opcode = 0; /* error!, already printed, have a better way to handle this? */
140         }
141
142         memset(op, 0, sizeof(BMOperator));
143         op->type = opcode;
144         op->flag = opdefines[opcode]->flag;
145         
146         /* initialize the operator slot types */
147         for (i = 0; opdefines[opcode]->slottypes[i].type; i++) {
148                 op->slots[i].slottype = opdefines[opcode]->slottypes[i].type;
149                 op->slots[i].index = i;
150         }
151
152         /* callback */
153         op->exec = opdefines[opcode]->exec;
154
155         /* memarena, used for operator's slot buffers */
156         op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
157         BLI_memarena_use_calloc(op->arena);
158 }
159
160 /**
161  * \brief BMESH OPSTACK EXEC OP
162  *
163  * Executes a passed in operator.
164  *
165  * This handles the allocation and freeing of temporary flag
166  * layers and starting/stopping the modeling loop.
167  * Can be called from other operators exec callbacks as well.
168  */
169 void BMO_op_exec(BMesh *bm, BMOperator *op)
170 {
171         
172         BMO_push(bm, op);
173
174         if (bm->stackdepth == 2)
175                 bmesh_edit_begin(bm, op->flag);
176         op->exec(bm, op);
177         
178         if (bm->stackdepth == 2)
179                 bmesh_edit_end(bm, op->flag);
180         
181         BMO_pop(bm);
182 }
183
184 /**
185  * \brief BMESH OPSTACK FINISH OP
186  *
187  * Does housekeeping chores related to finishing up an operator.
188  */
189 void BMO_op_finish(BMesh *bm, BMOperator *op)
190 {
191         BMOpSlot *slot;
192         int i;
193
194         for (i = 0; opdefines[op->type]->slottypes[i].type; i++) {
195                 slot = &op->slots[i];
196                 if (slot->slottype == BMO_OP_SLOT_MAPPING) {
197                         if (slot->data.ghash)
198                                 BLI_ghash_free(slot->data.ghash, NULL, NULL);
199                 }
200         }
201
202         BLI_memarena_free(op->arena);
203
204 #ifdef DEBUG
205         BM_ELEM_INDEX_VALIDATE(bm, "post bmo", opdefines[op->type]->name);
206 #else
207         (void)bm;
208 #endif
209 }
210
211 /**
212  * \brief BMESH OPSTACK HAS SLOT
213  *
214  * \return Success if the slot if found.
215  */
216 int BMO_slot_exists(BMOperator *op, const char *slotname)
217 {
218         int slotcode = bmo_name_to_slotcode(opdefines[op->type], slotname);
219         return (slotcode >= 0);
220 }
221
222 /**
223  * \brief BMESH OPSTACK GET SLOT
224  *
225  * Returns a pointer to the slot of type 'slotcode'
226  */
227 BMOpSlot *BMO_slot_get(BMOperator *op, const char *slotname)
228 {
229         int slotcode = bmo_name_to_slotcode_check(opdefines[op->type], slotname);
230
231         if (slotcode < 0) {
232                 return &BMOpEmptySlot;
233         }
234
235         return &(op->slots[slotcode]);
236 }
237
238 /**
239  * \brief BMESH OPSTACK COPY SLOT
240  *
241  * Copies data from one slot to another.
242  */
243 void BMO_slot_copy(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
244 {
245         BMOpSlot *source_slot = BMO_slot_get(source_op, src);
246         BMOpSlot *dest_slot = BMO_slot_get(dest_op, dst);
247
248         if (source_slot == dest_slot)
249                 return;
250
251         if (source_slot->slottype != dest_slot->slottype) {
252                 /* possibly assert here? */
253                 return;
254         }
255
256         if (dest_slot->slottype  == BMO_OP_SLOT_ELEMENT_BUF) {
257                 /* do buffer copy */
258                 dest_slot->data.buf = NULL;
259                 dest_slot->len = source_slot->len;
260                 if (dest_slot->len) {
261                         const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
262                         dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
263                         memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
264                 }
265         }
266         else if (dest_slot->slottype  == BMO_OP_SLOT_MAPPING) {
267                 GHashIterator it;
268                 BMOElemMapping *srcmap, *dstmap;
269
270                 /* sanity check */
271                 if (!source_slot->data.ghash) {
272                         return;
273                 }
274
275                 if (!dest_slot->data.ghash) {
276                         dest_slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
277                                                                                                   BLI_ghashutil_ptrcmp, "bmesh operator 2");
278                 }
279
280                 BLI_ghashIterator_init(&it, source_slot->data.ghash);
281                 for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
282                           BLI_ghashIterator_step(&it))
283                 {
284                         dstmap = BLI_memarena_alloc(dest_op->arena, sizeof(*dstmap) + srcmap->len);
285
286                         dstmap->element = srcmap->element;
287                         dstmap->len = srcmap->len;
288                         memcpy(dstmap + 1, srcmap + 1, srcmap->len);
289
290                         BLI_ghash_insert(dest_slot->data.ghash, dstmap->element, dstmap);
291                 }
292         }
293         else {
294                 dest_slot->data = source_slot->data;
295         }
296 }
297
298 /*
299  * BMESH OPSTACK SET XXX
300  *
301  * Sets the value of a slot depending on it's type
302  */
303
304 void BMO_slot_float_set(BMOperator *op, const char *slotname, const float f)
305 {
306         BMOpSlot *slot = BMO_slot_get(op, slotname);
307         BLI_assert(slot->slottype == BMO_OP_SLOT_FLT);
308         if (!(slot->slottype == BMO_OP_SLOT_FLT))
309                 return;
310
311         slot->data.f = f;
312 }
313
314 void BMO_slot_int_set(BMOperator *op, const char *slotname, const int i)
315 {
316         BMOpSlot *slot = BMO_slot_get(op, slotname);
317         BLI_assert(slot->slottype == BMO_OP_SLOT_INT);
318         if (!(slot->slottype == BMO_OP_SLOT_INT))
319                 return;
320
321         slot->data.i = i;
322 }
323
324 void BMO_slot_bool_set(BMOperator *op, const char *slotname, const int i)
325 {
326         BMOpSlot *slot = BMO_slot_get(op, slotname);
327         BLI_assert(slot->slottype == BMO_OP_SLOT_BOOL);
328         if (!(slot->slottype == BMO_OP_SLOT_BOOL))
329                 return;
330
331         slot->data.i = i;
332 }
333
334 /* only supports square mats */
335 void BMO_slot_mat_set(BMOperator *op, const char *slotname, const float *mat, int size)
336 {
337         BMOpSlot *slot = BMO_slot_get(op, slotname);
338         BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
339         if (!(slot->slottype == BMO_OP_SLOT_MAT))
340                 return;
341
342         slot->len = 4;
343         slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
344         
345         if (size == 4) {
346                 memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
347         }
348         else if (size == 3) {
349                 copy_m4_m3(slot->data.p, (float (*)[3])mat);
350         }
351         else {
352                 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
353
354                 memset(slot->data.p, 0, sizeof(float) * 4 * 4);
355         }
356 }
357
358 void BMO_slot_mat4_get(BMOperator *op, const char *slotname, float r_mat[4][4])
359 {
360         BMOpSlot *slot = BMO_slot_get(op, slotname);
361         BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
362         if (!(slot->slottype == BMO_OP_SLOT_MAT))
363                 return;
364
365         copy_m4_m4(r_mat, (float (*)[4])slot->data.p);
366 }
367
368 void BMO_slot_mat3_set(BMOperator *op, const char *slotname, float r_mat[3][3])
369 {
370         BMOpSlot *slot = BMO_slot_get(op, slotname);
371         BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
372         if (!(slot->slottype == BMO_OP_SLOT_MAT))
373                 return;
374
375         copy_m3_m4(r_mat, slot->data.p);
376 }
377
378 void BMO_slot_ptr_set(BMOperator *op, const char *slotname, void *p)
379 {
380         BMOpSlot *slot = BMO_slot_get(op, slotname);
381         BLI_assert(slot->slottype == BMO_OP_SLOT_PNT);
382         if (!(slot->slottype == BMO_OP_SLOT_PNT))
383                 return;
384
385         slot->data.p = p;
386 }
387
388 void BMO_slot_vec_set(BMOperator *op, const char *slotname, const float vec[3])
389 {
390         BMOpSlot *slot = BMO_slot_get(op, slotname);
391         BLI_assert(slot->slottype == BMO_OP_SLOT_VEC);
392         if (!(slot->slottype == BMO_OP_SLOT_VEC))
393                 return;
394
395         copy_v3_v3(slot->data.vec, vec);
396 }
397
398
399 float BMO_slot_float_get(BMOperator *op, const char *slotname)
400 {
401         BMOpSlot *slot = BMO_slot_get(op, slotname);
402         BLI_assert(slot->slottype == BMO_OP_SLOT_FLT);
403         if (!(slot->slottype == BMO_OP_SLOT_FLT))
404                 return 0.0f;
405
406         return slot->data.f;
407 }
408
409 int BMO_slot_int_get(BMOperator *op, const char *slotname)
410 {
411         BMOpSlot *slot = BMO_slot_get(op, slotname);
412         BLI_assert(slot->slottype == BMO_OP_SLOT_INT);
413         if (!(slot->slottype == BMO_OP_SLOT_INT))
414                 return 0;
415
416         return slot->data.i;
417 }
418
419 int BMO_slot_bool_get(BMOperator *op, const char *slotname)
420 {
421         BMOpSlot *slot = BMO_slot_get(op, slotname);
422         BLI_assert(slot->slottype == BMO_OP_SLOT_BOOL);
423         if (!(slot->slottype == BMO_OP_SLOT_BOOL))
424                 return 0;
425
426         return slot->data.i;
427 }
428
429
430 void *BMO_slot_ptr_get(BMOperator *op, const char *slotname)
431 {
432         BMOpSlot *slot = BMO_slot_get(op, slotname);
433         BLI_assert(slot->slottype == BMO_OP_SLOT_PNT);
434         if (!(slot->slottype == BMO_OP_SLOT_PNT))
435                 return NULL;
436
437         return slot->data.p;
438 }
439
440 void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3])
441 {
442         BMOpSlot *slot = BMO_slot_get(op, slotname);
443         BLI_assert(slot->slottype == BMO_OP_SLOT_VEC);
444         if (!(slot->slottype == BMO_OP_SLOT_VEC))
445                 return;
446
447         copy_v3_v3(r_vec, slot->data.vec);
448 }
449
450 /*
451  * BMO_COUNTFLAG
452  *
453  * Counts the number of elements of a certain type that
454  * have a specific flag set.
455  *
456  */
457
458 int BMO_mesh_flag_count(BMesh *bm, const short oflag, const char htype)
459 {
460         BMIter elements;
461         int count = 0;
462         BMElemF *ele_f;
463
464         if (htype & BM_VERT) {
465                 for (ele_f = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
466                         if (BMO_elem_flag_test(bm, ele_f, oflag))
467                                 count++;
468                 }
469         }
470         if (htype & BM_EDGE) {
471                 for (ele_f = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
472                         if (BMO_elem_flag_test(bm, ele_f, oflag))
473                                 count++;
474                 }
475         }
476         if (htype & BM_FACE) {
477                 for (ele_f = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
478                         if (BMO_elem_flag_test(bm, ele_f, oflag))
479                                 count++;
480                 }
481         }
482
483         return count;
484 }
485
486 void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
487 {
488         const char iter_types[3] = {BM_VERTS_OF_MESH,
489                                     BM_EDGES_OF_MESH,
490                                     BM_FACES_OF_MESH};
491
492         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
493
494         BMIter iter;
495         BMElemF *ele;
496         int i;
497
498         for (i = 0; i < 3; i++) {
499                 if (htype & flag_types[i]) {
500                         BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
501                                 BMO_elem_flag_disable(bm, ele, oflag);
502                         }
503                 }
504         }
505 }
506
507 int BMO_slot_buffer_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
508 {
509         BMOpSlot *slot = BMO_slot_get(op, slotname);
510         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
511         
512         /* check if its actually a buffer */
513         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
514                 return 0;
515
516         return slot->len;
517 }
518
519 int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
520 {
521         BMOpSlot *slot = BMO_slot_get(op, slotname);
522         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
523         
524         /* check if its actually a buffer */
525         if (!(slot->slottype == BMO_OP_SLOT_MAPPING))
526                 return 0;
527
528         return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
529 }
530
531 /* inserts a key/value mapping into a mapping slot.  note that it copies the
532  * value, it doesn't store a reference to it. */
533
534 void BMO_slot_map_insert(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
535                          void *element, void *data, int len)
536 {
537         BMOElemMapping *mapping;
538         BMOpSlot *slot = BMO_slot_get(op, slotname);
539         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
540
541         mapping = (BMOElemMapping *) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
542
543         mapping->element = (BMHeader *) element;
544         mapping->len = len;
545         memcpy(mapping + 1, data, len);
546
547         if (!slot->data.ghash) {
548                 slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
549                                                  BLI_ghashutil_ptrcmp, "bmesh op");
550         }
551
552         BLI_ghash_insert(slot->data.ghash, element, mapping);
553 }
554
555 #if 0
556 void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slotcode, int totadd)
557 {
558         BMOpSlot *slot = &op->slots[slotcode];
559         void *tmp;
560         ssize_t allocsize;
561         
562         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
563
564         /* check if its actually a buffer */
565         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
566                 return NULL;
567
568         if (slot->flag & BMOS_DYNAMIC_ARRAY) {
569                 if (slot->len >= slot->size) {
570                         slot->size = (slot->size + 1 + totadd) * 2;
571
572                         allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size;
573
574                         tmp = slot->data.buf;
575                         slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
576                         memcpy(slot->data.buf, tmp, allocsize);
577                         MEM_freeN(tmp);
578                 }
579
580                 slot->len += totadd;
581         }
582         else {
583                 slot->flag |= BMOS_DYNAMIC_ARRAY;
584                 slot->len += totadd;
585                 slot->size = slot->len + 2;
586
587                 allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len;
588
589                 tmp = slot->data.buf;
590                 slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
591                 memcpy(slot->data.buf, tmp, allocsize);
592         }
593
594         return slot->data.buf;
595 }
596 #endif
597
598 void BMO_slot_map_to_flag(BMesh *bm, BMOperator *op, const char *slotname,
599                           const short oflag, const char htype)
600 {
601         GHashIterator it;
602         BMOpSlot *slot = BMO_slot_get(op, slotname);
603         BMElemF *ele_f;
604
605         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
606
607         /* sanity check */
608         if (!slot->data.ghash) return;
609
610         BLI_ghashIterator_init(&it, slot->data.ghash);
611         for ( ; (ele_f = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
612                 if (ele_f->head.htype & htype) {
613                         BMO_elem_flag_enable(bm, ele_f, oflag);
614                 }
615         }
616 }
617
618 static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slotname, int len)
619 {
620         BMOpSlot *slot = BMO_slot_get(op, slotname);
621         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
622
623         /* check if its actually a buffer */
624         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
625                 return NULL;
626         
627         slot->len = len;
628         if (len)
629                 slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slottype] * len);
630         return slot->data.buf;
631 }
632
633 /**
634  * \brief BMO_ALL_TO_SLOT
635  *
636  * Copies all elements of a certain type into an operator slot.
637  */
638 static void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
639 {
640         BMIter elements;
641         BMHeader *e;
642         BMOpSlot *output = BMO_slot_get(op, slotname);
643         int totelement = 0, i = 0;
644         
645         if (htype & BM_VERT) totelement += bm->totvert;
646         if (htype & BM_EDGE) totelement += bm->totedge;
647         if (htype & BM_FACE) totelement += bm->totface;
648
649         if (totelement) {
650                 bmo_slot_buffer_alloc(op, slotname, totelement);
651
652                 if (htype & BM_VERT) {
653                         for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
654                                 ((BMHeader **)output->data.p)[i] = e;
655                                 i++;
656                         }
657                 }
658
659                 if (htype & BM_EDGE) {
660                         for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
661                                 ((BMHeader **)output->data.p)[i] = e;
662                                 i++;
663                         }
664                 }
665
666                 if (htype & BM_FACE) {
667                         for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
668                                 ((BMHeader **)output->data.p)[i] = e;
669                                 i++;
670                         }
671                 }
672         }
673 }
674
675 /**
676  * \brief BMO_HEADERFLAG_TO_SLOT
677  *
678  * Copies elements of a certain type, which have a certain header flag set
679  * into a slot for an operator.
680  */
681 void BMO_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, const char *slotname,
682                                 const char hflag, const char htype)
683 {
684         BMIter elements;
685         BMElem *ele;
686         BMOpSlot *output = BMO_slot_get(op, slotname);
687         int totelement = 0, i = 0;
688         
689         totelement = BM_mesh_count_flag(bm, htype, hflag, TRUE);
690
691         if (totelement) {
692                 bmo_slot_buffer_alloc(op, slotname, totelement);
693
694                 if (htype & BM_VERT) {
695                         for (ele = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
696                                 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) && BM_elem_flag_test(ele, hflag)) {
697                                         ((BMElem **)output->data.p)[i] = ele;
698                                         i++;
699                                 }
700                         }
701                 }
702
703                 if (htype & BM_EDGE) {
704                         for (ele = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
705                                 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) && BM_elem_flag_test(ele, hflag)) {
706                                         ((BMElem **)output->data.p)[i] = ele;
707                                         i++;
708                                 }
709                         }
710                 }
711
712                 if (htype & BM_FACE) {
713                         for (ele = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
714                                 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) && BM_elem_flag_test(ele, hflag)) {
715                                         ((BMElem **)output->data.p)[i] = ele;
716                                         i++;
717                                 }
718                         }
719                 }
720         }
721         else {
722                 output->len = 0;
723         }
724 }
725
726 /**
727  * \brief BMO_FLAG_TO_SLOT
728  *
729  * Copies elements of a certain type, which have a certain flag set
730  * into an output slot for an operator.
731  */
732 void BMO_slot_buffer_from_flag(BMesh *bm, BMOperator *op, const char *slotname,
733                                const short oflag, const char htype)
734 {
735         BMIter elements;
736         BMOpSlot *slot = BMO_slot_get(op, slotname);
737         int totelement = BMO_mesh_flag_count(bm, oflag, htype), i = 0;
738
739         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
740
741         if (totelement) {
742                 BMHeader *ele;
743                 BMHeader **ele_array;
744
745                 bmo_slot_buffer_alloc(op, slotname, totelement);
746
747                 ele_array = (BMHeader **)slot->data.p;
748
749                 if (htype & BM_VERT) {
750                         for (ele = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
751                                 if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
752                                         ele_array[i] = ele;
753                                         i++;
754                                 }
755                         }
756                 }
757
758                 if (htype & BM_EDGE) {
759                         for (ele = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
760                                 if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
761                                         ele_array[i] = ele;
762                                         i++;
763                                 }
764                         }
765                 }
766
767                 if (htype & BM_FACE) {
768                         for (ele = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
769                                 if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
770                                         ele_array[i] = ele;
771                                         i++;
772                                 }
773                         }
774                 }
775         }
776         else {
777                 slot->len = 0;
778         }
779 }
780
781 /**
782  * \brief BMO_FLAG_BUFFER
783  *
784  * Header Flags elements in a slots buffer, automatically
785  * using the selection API where appropriate.
786  */
787 void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slotname,
788                                   const char hflag, const char htype, char do_flush_select)
789 {
790         BMOpSlot *slot = BMO_slot_get(op, slotname);
791         BMElem **data =  slot->data.p;
792         int i;
793
794         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
795
796         if (!(hflag & BM_ELEM_SELECT)) {
797                 do_flush_select = FALSE;
798         }
799
800         for (i = 0; i < slot->len; i++) {
801                 if (!(htype & data[i]->head.htype))
802                         continue;
803
804                 if (do_flush_select) {
805                         BM_elem_select_set(bm, data[i], TRUE);
806                 }
807                 BM_elem_flag_enable(data[i], hflag);
808         }
809 }
810
811 /**
812  * \brief BMO_FLAG_BUFFER
813  *
814  * Removes flags from elements in a slots buffer, automatically
815  * using the selection API where appropriate.
816  */
817 void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slotname,
818                                    const char hflag, const char htype, char do_flush_select)
819 {
820         BMOpSlot *slot = BMO_slot_get(op, slotname);
821         BMElem **data =  slot->data.p;
822         int i;
823
824         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
825
826         if (!(hflag & BM_ELEM_SELECT)) {
827                 do_flush_select = FALSE;
828         }
829
830         for (i = 0; i < slot->len; i++) {
831                 if (!(htype & data[i]->head.htype))
832                         continue;
833
834                 if (do_flush_select) {
835                         BM_elem_select_set(bm, data[i], FALSE);
836                 }
837
838                 BM_elem_flag_disable(data[i], hflag);
839         }
840 }
841 int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
842 {
843         int count = 0;
844
845         if (v->e) {
846                 BMEdge *curedge;
847                 const int len = bmesh_disk_count(v);
848                 int i;
849                 
850                 for (i = 0, curedge = v->e; i < len; i++) {
851                         if (BMO_elem_flag_test(bm, curedge, oflag))
852                                 count++;
853                         curedge = bmesh_disk_edge_next(curedge, v);
854                 }
855         }
856
857         return count;
858 }
859
860 /**
861  * \brief BMO_FLAG_BUFFER
862  *
863  * Flags elements in a slots buffer
864  */
865 void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slotname,
866                                  const short oflag, const char htype)
867 {
868         BMOpSlot *slot = BMO_slot_get(op, slotname);
869         BMHeader **data =  slot->data.p;
870         int i;
871
872         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
873
874         for (i = 0; i < slot->len; i++) {
875                 if (!(htype & data[i]->htype))
876                         continue;
877
878                 BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
879         }
880 }
881
882 /**
883  * \brief BMO_FLAG_BUFFER
884  *
885  * Removes flags from elements in a slots buffer
886  */
887 void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slotname,
888                                   const short oflag, const char htype)
889 {
890         BMOpSlot *slot = BMO_slot_get(op, slotname);
891         BMHeader **data =  slot->data.p;
892         int i;
893
894         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
895
896         for (i = 0; i < slot->len; i++) {
897                 if (!(htype & data[i]->htype))
898                         continue;
899
900                 BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
901         }
902 }
903
904
905 /**
906  * \brief ALLOC/FREE FLAG LAYER
907  *
908  * Used by operator stack to free/allocate
909  * private flag data. This is allocated
910  * using a mempool so the allocation/frees
911  * should be quite fast.
912  *
913  * BMESH_TODO:
914  * Investigate not freeing flag layers until
915  * all operators have been executed. This would
916  * save a lot of realloc potentially.
917  */
918 static void bmo_flag_layer_alloc(BMesh *bm)
919 {
920         BMElemF *ele;
921         /* set the index values since we are looping over all data anyway,
922          * may save time later on */
923         int i;
924
925         BMIter iter;
926         BLI_mempool *oldpool = bm->toolflagpool;                /* old flag pool */
927         BLI_mempool *newpool;
928         void *oldflags;
929
930         /* store memcpy size for reuse */
931         const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
932         
933         bm->totflags++;
934
935         /* allocate new flag poo */
936         bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, 512, 512, 0);
937         
938         /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
939         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
940                 oldflags = ele->oflags;
941                 ele->oflags = BLI_mempool_calloc(newpool);
942                 memcpy(ele->oflags, oldflags, old_totflags_size);
943                 BM_elem_index_set(ele, i); /* set_inline */
944         }
945         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
946                 oldflags = ele->oflags;
947                 ele->oflags = BLI_mempool_calloc(newpool);
948                 memcpy(ele->oflags, oldflags, old_totflags_size);
949                 BM_elem_index_set(ele, i); /* set_inline */
950         }
951         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
952                 oldflags = ele->oflags;
953                 ele->oflags = BLI_mempool_calloc(newpool);
954                 memcpy(ele->oflags, oldflags, old_totflags_size);
955                 BM_elem_index_set(ele, i); /* set_inline */
956         }
957
958         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
959
960         BLI_mempool_destroy(oldpool);
961 }
962
963 static void bmo_flag_layer_free(BMesh *bm)
964 {
965         BMElemF *ele;
966         /* set the index values since we are looping over all data anyway,
967          * may save time later on */
968         int i;
969
970         BMIter iter;
971         BLI_mempool *oldpool = bm->toolflagpool;
972         BLI_mempool *newpool;
973         void *oldflags;
974         
975         /* store memcpy size for reuse */
976         const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
977
978         /* de-increment the totflags first.. */
979         bm->totflags--;
980         /* allocate new flag poo */
981         bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, BLI_MEMPOOL_SYSMALLOC);
982         
983         /* now go through and memcpy all the flag */
984         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
985                 oldflags = ele->oflags;
986                 ele->oflags = BLI_mempool_calloc(newpool);
987                 memcpy(ele->oflags, oldflags, new_totflags_size);
988                 BM_elem_index_set(ele, i); /* set_inline */
989         }
990         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
991                 oldflags = ele->oflags;
992                 ele->oflags = BLI_mempool_calloc(newpool);
993                 memcpy(ele->oflags, oldflags, new_totflags_size);
994                 BM_elem_index_set(ele, i); /* set_inline */
995         }
996         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
997                 oldflags = ele->oflags;
998                 ele->oflags = BLI_mempool_calloc(newpool);
999                 memcpy(ele->oflags, oldflags, new_totflags_size);
1000                 BM_elem_index_set(ele, i); /* set_inline */
1001         }
1002
1003         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1004
1005         BLI_mempool_destroy(oldpool);
1006 }
1007
1008 static void bmo_flag_layer_clear(BMesh *bm)
1009 {
1010         BMElemF *ele;
1011         /* set the index values since we are looping over all data anyway,
1012          * may save time later on */
1013         int i;
1014
1015         BMIter iter;
1016         const int totflags_offset = bm->totflags - 1;
1017
1018         /* now go through and memcpy all the flag */
1019         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
1020                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1021                 BM_elem_index_set(ele, i); /* set_inline */
1022         }
1023         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
1024                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1025                 BM_elem_index_set(ele, i); /* set_inline */
1026         }
1027         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
1028                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1029                 BM_elem_index_set(ele, i); /* set_inline */
1030         }
1031
1032         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1033 }
1034
1035 void *BMO_slot_buffer_elem_first(BMOperator *op, const char *slotname)
1036 {
1037         BMOpSlot *slot = BMO_slot_get(op, slotname);
1038         
1039         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
1040                 return NULL;
1041
1042         return slot->data.buf ? *(void **)slot->data.buf : NULL;
1043 }
1044
1045 /**
1046  * \brief New Iterator
1047  *
1048  * \param restrictmask restricts the iteration to certain element types
1049  * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
1050  * over an element buffer (not a mapping). */
1051 void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
1052                    const char *slotname, const char restrictmask)
1053 {
1054         BMOpSlot *slot = BMO_slot_get(op, slotname);
1055
1056         memset(iter, 0, sizeof(BMOIter));
1057
1058         iter->slot = slot;
1059         iter->cur = 0;
1060         iter->restrictmask = restrictmask;
1061
1062         if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1063                 if (iter->slot->data.ghash) {
1064                         BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1065                 }
1066                 else {
1067                         return NULL;
1068                 }
1069         }
1070
1071         return BMO_iter_step(iter);
1072 }
1073
1074 void *BMO_iter_step(BMOIter *iter)
1075 {
1076         if (iter->slot->slottype == BMO_OP_SLOT_ELEMENT_BUF) {
1077                 BMHeader *h;
1078
1079                 if (iter->cur >= iter->slot->len) {
1080                         return NULL;
1081                 }
1082
1083                 h = ((void **)iter->slot->data.buf)[iter->cur++];
1084                 while (!(iter->restrictmask & h->htype)) {
1085                         if (iter->cur >= iter->slot->len) {
1086                                 return NULL;
1087                         }
1088
1089                         h = ((void **)iter->slot->data.buf)[iter->cur++];
1090                 }
1091
1092                 return h;
1093         }
1094         else if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1095                 BMOElemMapping *map;
1096                 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1097                 map = BLI_ghashIterator_getValue(&iter->giter);
1098                 
1099                 iter->val = map + 1;
1100
1101                 BLI_ghashIterator_step(&iter->giter);
1102
1103                 return ret;
1104         }
1105
1106         return NULL;
1107 }
1108
1109 /* used for iterating over mapping */
1110 void *BMO_iter_map_value(BMOIter *iter)
1111 {
1112         return iter->val;
1113 }
1114
1115 void *BMO_iter_map_value_p(BMOIter *iter)
1116 {
1117         return *((void **)iter->val);
1118 }
1119
1120 float BMO_iter_map_value_f(BMOIter *iter)
1121 {
1122         return *((float *)iter->val);
1123 }
1124
1125 /* error syste */
1126 typedef struct BMOpError {
1127         struct BMOpError *next, *prev;
1128         int errorcode;
1129         BMOperator *op;
1130         const char *msg;
1131 } BMOpError;
1132
1133 void BMO_error_clear(BMesh *bm)
1134 {
1135         while (BMO_error_pop(bm, NULL, NULL));
1136 }
1137
1138 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1139 {
1140         BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1141         
1142         err->errorcode = errcode;
1143         if (!msg) msg = bmo_error_messages[errcode];
1144         err->msg = msg;
1145         err->op = owner;
1146         
1147         BLI_addhead(&bm->errorstack, err);
1148 }
1149
1150 int BMO_error_occurred(BMesh *bm)
1151 {
1152         return bm->errorstack.first != NULL;
1153 }
1154
1155 /* returns error code or 0 if no erro */
1156 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1157 {
1158         BMOpError *err = bm->errorstack.first;
1159         if (!err) {
1160                 return 0;
1161         }
1162
1163         if (msg) *msg = err->msg;
1164         if (op) *op = err->op;
1165         
1166         return err->errorcode;
1167 }
1168
1169 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1170 {
1171         int errorcode = BMO_error_get(bm, msg, op);
1172         
1173         if (errorcode) {
1174                 BMOpError *err = bm->errorstack.first;
1175                 
1176                 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1177                 MEM_freeN(err);
1178         }
1179
1180         return errorcode;
1181 }
1182
1183
1184 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1185
1186 static int bmo_name_to_slotcode(BMOpDefine *def, const char *name)
1187 {
1188         int i;
1189
1190         for (i = 0; def->slottypes[i].type; i++) {
1191                 if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
1192                         return i;
1193                 }
1194         }
1195
1196         return -1;
1197 }
1198
1199 static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name)
1200 {
1201         int i = bmo_name_to_slotcode(def, name);
1202         if (i < 0) {
1203                 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1204         }
1205
1206         return i;
1207 }
1208
1209 static int bmo_opname_to_opcode(const char *opname)
1210 {
1211         int i;
1212
1213         for (i = 0; i < bmesh_total_ops; i++) {
1214                 if (!strcmp(opname, opdefines[i]->name)) {
1215                         return i;
1216                 }
1217         }
1218
1219         fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1220         return -1;
1221 }
1222
1223 /* Example:
1224  * BMO_op_callf(bm, "del %i %hv", DEL_ONLYFACES, BM_ELEM_SELECT);
1225  *
1226  *  i - int
1227  *  b - boolean (same as int but 1/0 only)
1228  *  f - float
1229  *  hv - header flagged verts (hflag)
1230  *  he - header flagged edges (hflag)
1231  *  hf - header flagged faces (hflag)
1232  *  fv - flagged verts (oflag)
1233  *  fe - flagged edges (oflag)
1234  *  ff - flagged faces (oflag)
1235  */
1236
1237 int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1238 {
1239         BMOpDefine *def;
1240         char *opname, *ofmt, *fmt;
1241         char slotname[64] = {0};
1242         int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, ret, type, state;
1243         int noslot = 0;
1244
1245
1246         /* basic useful info to help find where bmop formatting strings fail */
1247         int lineno = -1;
1248 #   define GOTO_ERROR { lineno = __LINE__; goto error; }
1249
1250
1251         /* we muck around in here, so dup i */
1252         fmt = ofmt = BLI_strdup(_fmt);
1253         
1254         /* find operator nam */
1255         i = strcspn(fmt, " \t");
1256
1257         opname = fmt;
1258         if (!opname[i]) noslot = 1;
1259         opname[i] = '\0';
1260
1261         fmt += i + (noslot ? 0 : 1);
1262         
1263         i = bmo_opname_to_opcode(opname);
1264
1265         if (i == -1) {
1266                 MEM_freeN(ofmt);
1267                 return FALSE;
1268         }
1269
1270         BMO_op_init(bm, op, opname);
1271         def = opdefines[i];
1272         
1273         i = 0;
1274         state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1275
1276         while (*fmt) {
1277                 if (state) {
1278                         /* jump past leading whitespac */
1279                         i = strspn(fmt, " \t");
1280                         fmt += i;
1281                         
1282                         /* ignore trailing whitespac */
1283                         if (!fmt[i])
1284                                 break;
1285
1286                         /* find end of slot name.  currently this is
1287                          * a little flexible, allowing "slot=%f",
1288                          * "slot %f", "slot%f", and "slot\t%f". */
1289                         i = strcspn(fmt, "= \t%");
1290                         if (!fmt[i]) GOTO_ERROR;
1291
1292                         fmt[i] = 0;
1293
1294                         if (bmo_name_to_slotcode_check(def, fmt) < 0) GOTO_ERROR;
1295                         
1296                         BLI_strncpy(slotname, fmt, sizeof(slotname));
1297                         
1298                         state = 0;
1299                         fmt += i;
1300                 }
1301                 else {
1302                         switch (*fmt) {
1303                                 case ' ':
1304                                 case '\t':
1305                                 case '=':
1306                                 case '%':
1307                                         break;
1308                                 case 'm': {
1309                                         int size, c;
1310
1311                                         c = NEXT_CHAR(fmt);
1312                                         fmt++;
1313
1314                                         if (c == '3') size = 3;
1315                                         else if (c == '4') size = 4;
1316                                         else GOTO_ERROR;
1317
1318                                         BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
1319                                         state = 1;
1320                                         break;
1321                                 }
1322                                 case 'v': {
1323                                         BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
1324                                         state = 1;
1325                                         break;
1326                                 }
1327                                 case 'e': {
1328                                         BMHeader *ele = va_arg(vlist, void *);
1329                                         BMOpSlot *slot = BMO_slot_get(op, slotname);
1330
1331                                         slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1332                                         slot->len = 1;
1333                                         *((void **)slot->data.buf) = ele;
1334
1335                                         state = 1;
1336                                         break;
1337                                 }
1338                                 case 's': {
1339                                         BMOperator *op2 = va_arg(vlist, void *);
1340                                         const char *slotname2 = va_arg(vlist, char *);
1341
1342                                         BMO_slot_copy(op2, op, slotname2, slotname);
1343                                         state = 1;
1344                                         break;
1345                                 }
1346                                 case 'i':
1347                                         BMO_slot_int_set(op, slotname, va_arg(vlist, int));
1348                                         state = 1;
1349                                         break;
1350                                 case 'b':
1351                                         BMO_slot_bool_set(op, slotname, va_arg(vlist, int));
1352                                         state = 1;
1353                                         break;
1354                                 case 'p':
1355                                         BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
1356                                         state = 1;
1357                                         break;
1358                                 case 'f':
1359                                 case 'h':
1360                                 case 'a':
1361                                         type = *fmt;
1362
1363                                         if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\t' || NEXT_CHAR(fmt) == '\0') {
1364                                                 BMO_slot_float_set(op, slotname, va_arg(vlist, double));
1365                                         }
1366                                         else {
1367                                                 ret = 0;
1368                                                 stop = 0;
1369                                                 while (1) {
1370                                                         switch (NEXT_CHAR(fmt)) {
1371                                                                 case 'f': ret |= BM_FACE; break;
1372                                                                 case 'e': ret |= BM_EDGE; break;
1373                                                                 case 'v': ret |= BM_VERT; break;
1374                                                                 default:
1375                                                                         stop = 1;
1376                                                                         break;
1377                                                         }
1378                                                         if (stop) {
1379                                                                 break;
1380                                                         }
1381
1382                                                         fmt++;
1383                                                 }
1384
1385                                                 if (type == 'h') {
1386                                                         BMO_slot_buffer_from_hflag(bm, op, slotname, va_arg(vlist, int), ret);
1387                                                 }
1388                                                 else if (type == 'a') {
1389                                                         BMO_slot_buffer_from_all(bm, op, slotname, ret);
1390                                                 }
1391                                                 else {
1392                                                         BMO_slot_buffer_from_flag(bm, op, slotname, va_arg(vlist, int), ret);
1393                                                 }
1394                                         }
1395
1396                                         state = 1;
1397                                         break;
1398                                 default:
1399                                         fprintf(stderr,
1400                                                 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1401                                                 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1402                                         break;
1403                         }
1404                 }
1405                 fmt++;
1406         }
1407
1408         MEM_freeN(ofmt);
1409         return TRUE;
1410 error:
1411
1412         /* non urgent todo - explain exactly what is failing */
1413         fprintf(stderr,
1414                 "%s: error parsing formatting string, %d in '%s'\n    see - %s:%d\n",
1415                 __func__, (int)(fmt - ofmt), _fmt, __FILE__, lineno);
1416         MEM_freeN(ofmt);
1417
1418         BMO_op_finish(bm, op);
1419         return FALSE;
1420
1421 #undef GOTO_ERROR
1422
1423 }
1424
1425
1426 int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1427 {
1428         va_list list;
1429
1430         va_start(list, fmt);
1431         if (!BMO_op_vinitf(bm, op, fmt, list)) {
1432                 printf("%s: failed\n", __func__);
1433                 va_end(list);
1434                 return FALSE;
1435         }
1436         va_end(list);
1437
1438         return TRUE;
1439 }
1440
1441 int BMO_op_callf(BMesh *bm, const char *fmt, ...)
1442 {
1443         va_list list;
1444         BMOperator op;
1445
1446         va_start(list, fmt);
1447         if (!BMO_op_vinitf(bm, &op, fmt, list)) {
1448                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1449                 va_end(list);
1450                 return FALSE;
1451         }
1452
1453         BMO_op_exec(bm, &op);
1454         BMO_op_finish(bm, &op);
1455
1456         va_end(list);
1457         return TRUE;
1458 }