update doxygen comments for bmesh.
[blender-staging.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 "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         "Tesselation 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, "bmesh operator");
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                 return;
253         
254         if (dest_slot->slottype > BMO_OP_SLOT_VEC) {
255                 if (dest_slot->slottype != BMO_OP_SLOT_MAPPING) {
256                         /* do buffer copy */
257                         dest_slot->data.buf = NULL;
258                         dest_slot->len = source_slot->len;
259                         if (dest_slot->len) {
260                                 const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
261                                 dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
262                                 memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
263                         }
264                 }
265                 else {
266                         GHashIterator it;
267                         BMOElemMapping *srcmap, *dstmap;
268
269                         /* sanity check */
270                         if (!source_slot->data.ghash) return;
271                         
272                         if (!dest_slot->data.ghash) {
273                                 dest_slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
274                                                                       BLI_ghashutil_ptrcmp, "bmesh operator 2");
275                         }
276
277                         BLI_ghashIterator_init(&it, source_slot->data.ghash);
278                         for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
279                               BLI_ghashIterator_step(&it))
280                         {
281                                 dstmap = BLI_memarena_alloc(dest_op->arena, sizeof(*dstmap) + srcmap->len);
282
283                                 dstmap->element = srcmap->element;
284                                 dstmap->len = srcmap->len;
285                                 memcpy(dstmap + 1, srcmap + 1, srcmap->len);
286
287                                 BLI_ghash_insert(dest_slot->data.ghash, dstmap->element, dstmap);
288                         }
289                 }
290         }
291         else {
292                 dest_slot->data = source_slot->data;
293         }
294 }
295
296 /*
297  * BMESH OPSTACK SET XXX
298  *
299  * Sets the value of a slot depending on it's type
300  */
301
302 void BMO_slot_float_set(BMOperator *op, const char *slotname, const float f)
303 {
304         BMOpSlot *slot = BMO_slot_get(op, slotname);
305         BLI_assert(slot->slottype == BMO_OP_SLOT_FLT);
306         if (!(slot->slottype == BMO_OP_SLOT_FLT))
307                 return;
308
309         slot->data.f = f;
310 }
311
312 void BMO_slot_int_set(BMOperator *op, const char *slotname, const int i)
313 {
314         BMOpSlot *slot = BMO_slot_get(op, slotname);
315         BLI_assert(slot->slottype == BMO_OP_SLOT_INT);
316         if (!(slot->slottype == BMO_OP_SLOT_INT))
317                 return;
318
319         slot->data.i = i;
320 }
321
322 void BMO_slot_bool_set(BMOperator *op, const char *slotname, const int i)
323 {
324         BMOpSlot *slot = BMO_slot_get(op, slotname);
325         BLI_assert(slot->slottype == BMO_OP_SLOT_BOOL);
326         if (!(slot->slottype == BMO_OP_SLOT_BOOL))
327                 return;
328
329         slot->data.i = i;
330 }
331
332 /* only supports square mats */
333 void BMO_slot_mat_set(BMOperator *op, const char *slotname, const float *mat, int size)
334 {
335         BMOpSlot *slot = BMO_slot_get(op, slotname);
336         BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
337         if (!(slot->slottype == BMO_OP_SLOT_MAT))
338                 return;
339
340         slot->len = 4;
341         slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
342         
343         if (size == 4) {
344                 memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
345         }
346         else if (size == 3) {
347                 copy_m4_m3(slot->data.p, (float (*)[3])mat);
348         }
349         else {
350                 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
351
352                 memset(slot->data.p, 0, sizeof(float) * 4 * 4);
353         }
354 }
355
356 void BMO_slot_mat4_get(BMOperator *op, const char *slotname, float r_mat[4][4])
357 {
358         BMOpSlot *slot = BMO_slot_get(op, slotname);
359         BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
360         if (!(slot->slottype == BMO_OP_SLOT_MAT))
361                 return;
362
363         copy_m4_m4(r_mat, (float (*)[4])slot->data.p);
364 }
365
366 void BMO_slot_mat3_set(BMOperator *op, const char *slotname, float r_mat[3][3])
367 {
368         BMOpSlot *slot = BMO_slot_get(op, slotname);
369         BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
370         if (!(slot->slottype == BMO_OP_SLOT_MAT))
371                 return;
372
373         copy_m3_m4(r_mat, slot->data.p);
374 }
375
376 void BMO_slot_ptr_set(BMOperator *op, const char *slotname, void *p)
377 {
378         BMOpSlot *slot = BMO_slot_get(op, slotname);
379         BLI_assert(slot->slottype == BMO_OP_SLOT_PNT);
380         if (!(slot->slottype == BMO_OP_SLOT_PNT))
381                 return;
382
383         slot->data.p = p;
384 }
385
386 void BMO_slot_vec_set(BMOperator *op, const char *slotname, const float vec[3])
387 {
388         BMOpSlot *slot = BMO_slot_get(op, slotname);
389         BLI_assert(slot->slottype == BMO_OP_SLOT_VEC);
390         if (!(slot->slottype == BMO_OP_SLOT_VEC))
391                 return;
392
393         copy_v3_v3(slot->data.vec, vec);
394 }
395
396
397 float BMO_slot_float_get(BMOperator *op, const char *slotname)
398 {
399         BMOpSlot *slot = BMO_slot_get(op, slotname);
400         BLI_assert(slot->slottype == BMO_OP_SLOT_FLT);
401         if (!(slot->slottype == BMO_OP_SLOT_FLT))
402                 return 0.0f;
403
404         return slot->data.f;
405 }
406
407 int BMO_slot_int_get(BMOperator *op, const char *slotname)
408 {
409         BMOpSlot *slot = BMO_slot_get(op, slotname);
410         BLI_assert(slot->slottype == BMO_OP_SLOT_INT);
411         if (!(slot->slottype == BMO_OP_SLOT_INT))
412                 return 0;
413
414         return slot->data.i;
415 }
416
417 int BMO_slot_bool_get(BMOperator *op, const char *slotname)
418 {
419         BMOpSlot *slot = BMO_slot_get(op, slotname);
420         BLI_assert(slot->slottype == BMO_OP_SLOT_BOOL);
421         if (!(slot->slottype == BMO_OP_SLOT_BOOL))
422                 return 0;
423
424         return slot->data.i;
425 }
426
427
428 void *BMO_slot_ptr_get(BMOperator *op, const char *slotname)
429 {
430         BMOpSlot *slot = BMO_slot_get(op, slotname);
431         BLI_assert(slot->slottype == BMO_OP_SLOT_PNT);
432         if (!(slot->slottype == BMO_OP_SLOT_PNT))
433                 return NULL;
434
435         return slot->data.p;
436 }
437
438 void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3])
439 {
440         BMOpSlot *slot = BMO_slot_get(op, slotname);
441         BLI_assert(slot->slottype == BMO_OP_SLOT_VEC);
442         if (!(slot->slottype == BMO_OP_SLOT_VEC))
443                 return;
444
445         copy_v3_v3(r_vec, slot->data.vec);
446 }
447
448 /*
449  * BMO_COUNTFLAG
450  *
451  * Counts the number of elements of a certain type that
452  * have a specific flag set.
453  *
454  */
455
456 int BMO_mesh_flag_count(BMesh *bm, const short oflag, const char htype)
457 {
458         BMIter elements;
459         int count = 0;
460         BMElemF *ele_f;
461
462         if (htype & BM_VERT) {
463                 for (ele_f = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
464                         if (BMO_elem_flag_test(bm, ele_f, oflag))
465                                 count++;
466                 }
467         }
468         if (htype & BM_EDGE) {
469                 for (ele_f = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
470                         if (BMO_elem_flag_test(bm, ele_f, oflag))
471                                 count++;
472                 }
473         }
474         if (htype & BM_FACE) {
475                 for (ele_f = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
476                         if (BMO_elem_flag_test(bm, ele_f, oflag))
477                                 count++;
478                 }
479         }
480
481         return count;
482 }
483
484 void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
485 {
486         const char iter_types[3] = {BM_VERTS_OF_MESH,
487                                     BM_EDGES_OF_MESH,
488                                     BM_FACES_OF_MESH};
489
490         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
491
492         BMIter iter;
493         BMElemF *ele;
494         int i;
495
496         for (i = 0; i < 3; i++) {
497                 if (htype & flag_types[i]) {
498                         BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
499                                 BMO_elem_flag_disable(bm, ele, oflag);
500                         }
501                 }
502         }
503 }
504
505 int BMO_slot_buf_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
506 {
507         BMOpSlot *slot = BMO_slot_get(op, slotname);
508         BLI_assert(slot->slottype > BMO_OP_SLOT_VEC);
509         
510         /* check if its actually a buffer */
511         if (!(slot->slottype > BMO_OP_SLOT_VEC))
512                 return 0;
513
514         return slot->len;
515 }
516
517 int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
518 {
519         BMOpSlot *slot = BMO_slot_get(op, slotname);
520         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
521         
522         /* check if its actually a buffer */
523         if (!(slot->slottype == BMO_OP_SLOT_MAPPING))
524                 return 0;
525
526         return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
527 }
528
529 /* inserts a key/value mapping into a mapping slot.  note that it copies the
530  * value, it doesn't store a reference to it. */
531
532 void BMO_slot_map_insert(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
533                          void *element, void *data, int len)
534 {
535         BMOElemMapping *mapping;
536         BMOpSlot *slot = BMO_slot_get(op, slotname);
537
538         /*sanity check*/
539         if (slot->slottype != BMO_OP_SLOT_MAPPING) {
540                 return;
541         }
542
543         mapping = (BMOElemMapping *) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
544
545         mapping->element = (BMHeader *) element;
546         mapping->len = len;
547         memcpy(mapping + 1, data, len);
548
549         if (!slot->data.ghash) {
550                 slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
551                                                  BLI_ghashutil_ptrcmp, "bmesh op");
552         }
553
554         BLI_ghash_insert(slot->data.ghash, element, mapping);
555 }
556
557 #if 0
558 void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd)
559 {
560         BMOpSlot *slot = &op->slots[slotcode];
561         void *tmp;
562         ssize_t allocsize;
563         
564         /* check if its actually a buffer */
565         if (!(slot->slottype > BMO_OP_SLOT_VEC))
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,
599                           const char *slotname, const short oflag)
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->slottype != BMO_OP_SLOT_MAPPING) return;
609         if (!slot->data.ghash) return;
610
611         BLI_ghashIterator_init(&it, slot->data.ghash);
612         for ( ; (ele_f = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
613                 BMO_elem_flag_enable(bm, ele_f, oflag);
614         }
615 }
616
617 static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slotname, int len)
618 {
619         BMOpSlot *slot = BMO_slot_get(op, slotname);
620
621         BLI_assert(slot->slottype > BMO_OP_SLOT_VEC);
622
623         /* check if its actually a buffer */
624         if (!(slot->slottype > BMO_OP_SLOT_VEC))
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_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_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, 1);
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_from_flag(BMesh *bm, BMOperator *op, const char *slotname,
733                         const short oflag, const char htype)
734 {
735         BMIter elements;
736         BMHeader *ele;
737         BMOpSlot *output = BMO_slot_get(op, slotname);
738         int totelement = BMO_mesh_flag_count(bm, oflag, htype), i = 0;
739
740         BLI_assert(output->slottype > BMO_OP_SLOT_VEC);
741
742         if (totelement) {
743                 bmo_slot_buffer_alloc(op, slotname, totelement);
744
745                 if (htype & BM_VERT) {
746                         for (ele = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
747                                 if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
748                                         ((BMHeader **)output->data.p)[i] = ele;
749                                         i++;
750                                 }
751                         }
752                 }
753
754                 if (htype & BM_EDGE) {
755                         for (ele = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
756                                 if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
757                                         ((BMHeader **)output->data.p)[i] = ele;
758                                         i++;
759                                 }
760                         }
761                 }
762
763                 if (htype & BM_FACE) {
764                         for (ele = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
765                                 if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
766                                         ((BMHeader **)output->data.p)[i] = ele;
767                                         i++;
768                                 }
769                         }
770                 }
771         }
772         else {
773                 output->len = 0;
774         }
775 }
776
777 /**
778  * \brief BMO_FLAG_BUFFER
779  *
780  * Header Flags elements in a slots buffer, automatically
781  * using the selection API where appropriate.
782  */
783 void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slotname,
784                                   const char hflag, const char htype, char do_flush_select)
785 {
786         BMOpSlot *slot = BMO_slot_get(op, slotname);
787         BMElem **data =  slot->data.p;
788         int i;
789
790         BLI_assert(slot->slottype > BMO_OP_SLOT_VEC);
791
792         if (!(hflag & BM_ELEM_SELECT)) {
793                 do_flush_select = FALSE;
794         }
795
796         for (i = 0; i < slot->len; i++) {
797                 if (!(htype & data[i]->head.htype))
798                         continue;
799
800                 if (do_flush_select) {
801                         BM_elem_select_set(bm, data[i], TRUE);
802                 }
803                 BM_elem_flag_enable(data[i], hflag);
804         }
805 }
806
807 /**
808  * \brief BMO_FLAG_BUFFER
809  *
810  * Removes flags from elements in a slots buffer, automatically
811  * using the selection API where appropriate.
812  */
813 void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slotname,
814                                    const char hflag, const char htype, char do_flush_select)
815 {
816         BMOpSlot *slot = BMO_slot_get(op, slotname);
817         BMElem **data =  slot->data.p;
818         int i;
819
820         BLI_assert(slot->slottype > BMO_OP_SLOT_VEC);
821
822         if (!(hflag & BM_ELEM_SELECT)) {
823                 do_flush_select = FALSE;
824         }
825
826         for (i = 0; i < slot->len; i++) {
827                 if (!(htype & data[i]->head.htype))
828                         continue;
829
830                 if (do_flush_select) {
831                         BM_elem_select_set(bm, data[i], FALSE);
832                 }
833
834                 BM_elem_flag_disable(data[i], hflag);
835         }
836 }
837 int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
838 {
839         int count = 0;
840
841         if (v->e) {
842                 BMEdge *curedge;
843                 const int len = bmesh_disk_count(v);
844                 int i;
845                 
846                 for (i = 0, curedge = v->e; i < len; i++) {
847                         if (BMO_elem_flag_test(bm, curedge, oflag))
848                                 count++;
849                         curedge = bmesh_disk_edge_next(curedge, v);
850                 }
851         }
852
853         return count;
854 }
855
856 /**
857  * \brief BMO_FLAG_BUFFER
858  *
859  * Flags elements in a slots buffer
860  */
861 void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slotname,
862                                  const short oflag, const char htype)
863 {
864         BMOpSlot *slot = BMO_slot_get(op, slotname);
865         BMHeader **data =  slot->data.p;
866         int i;
867
868         BLI_assert(slot->slottype > BMO_OP_SLOT_VEC);
869
870         for (i = 0; i < slot->len; i++) {
871                 if (!(htype & data[i]->htype))
872                         continue;
873
874                 BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
875         }
876 }
877
878 /**
879  * \brief BMO_FLAG_BUFFER
880  *
881  * Removes flags from elements in a slots buffer
882  */
883 void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slotname,
884                                   const short oflag, const char htype)
885 {
886         BMOpSlot *slot = BMO_slot_get(op, slotname);
887         BMHeader **data =  slot->data.p;
888         int i;
889         
890         for (i = 0; i < slot->len; i++) {
891                 if (!(htype & data[i]->htype))
892                         continue;
893
894                 BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
895         }
896 }
897
898
899 /**
900  * \brief ALLOC/FREE FLAG LAYER
901  *
902  * Used by operator stack to free/allocate
903  * private flag data. This is allocated
904  * using a mempool so the allocation/frees
905  * should be quite fast.
906  *
907  * BMESH_TODO:
908  * Investigate not freeing flag layers until
909  * all operators have been executed. This would
910  * save a lot of realloc potentially.
911  */
912 static void bmo_flag_layer_alloc(BMesh *bm)
913 {
914         BMElemF *ele;
915         /* set the index values since we are looping over all data anyway,
916          * may save time later on */
917         int i;
918
919         BMIter iter;
920         BLI_mempool *oldpool = bm->toolflagpool;                /* old flag pool */
921         BLI_mempool *newpool;
922         void *oldflags;
923
924         /* store memcpy size for reuse */
925         const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
926         
927         bm->totflags++;
928
929         /* allocate new flag poo */
930         bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, 512, 512, FALSE, FALSE);
931         
932         /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
933         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
934                 oldflags = ele->oflags;
935                 ele->oflags = BLI_mempool_calloc(newpool);
936                 memcpy(ele->oflags, oldflags, old_totflags_size);
937                 BM_elem_index_set(ele, i); /* set_inline */
938         }
939         for (ele = BM_iter_new(&iter, bm, BM_EDGES_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_FACES_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
952         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
953
954         BLI_mempool_destroy(oldpool);
955 }
956
957 static void bmo_flag_layer_free(BMesh *bm)
958 {
959         BMElemF *ele;
960         /* set the index values since we are looping over all data anyway,
961          * may save time later on */
962         int i;
963
964         BMIter iter;
965         BLI_mempool *oldpool = bm->toolflagpool;
966         BLI_mempool *newpool;
967         void *oldflags;
968         
969         /* store memcpy size for reuse */
970         const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
971
972         /* de-increment the totflags first.. */
973         bm->totflags--;
974         /* allocate new flag poo */
975         bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, TRUE, FALSE);
976         
977         /* now go through and memcpy all the flag */
978         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
979                 oldflags = ele->oflags;
980                 ele->oflags = BLI_mempool_calloc(newpool);
981                 memcpy(ele->oflags, oldflags, new_totflags_size);
982                 BM_elem_index_set(ele, i); /* set_inline */
983         }
984         for (ele = BM_iter_new(&iter, bm, BM_EDGES_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_FACES_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
997         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
998
999         BLI_mempool_destroy(oldpool);
1000 }
1001
1002 static void bmo_flag_layer_clear(BMesh *bm)
1003 {
1004         BMElemF *ele;
1005         /* set the index values since we are looping over all data anyway,
1006          * may save time later on */
1007         int i;
1008
1009         BMIter iter;
1010         const int totflags_offset = bm->totflags - 1;
1011
1012         /* now go through and memcpy all the flag */
1013         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
1014                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1015                 BM_elem_index_set(ele, i); /* set_inline */
1016         }
1017         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
1018                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1019                 BM_elem_index_set(ele, i); /* set_inline */
1020         }
1021         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
1022                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1023                 BM_elem_index_set(ele, i); /* set_inline */
1024         }
1025
1026         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1027 }
1028
1029 void *BMO_slot_elem_first(BMOperator *op, const char *slotname)
1030 {
1031         BMOpSlot *slot = BMO_slot_get(op, slotname);
1032         
1033         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
1034                 return NULL;
1035
1036         return slot->data.buf ? *(void **)slot->data.buf : NULL;
1037 }
1038
1039 void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
1040                    const char *slotname, const char restrictmask)
1041 {
1042         BMOpSlot *slot = BMO_slot_get(op, slotname);
1043
1044         memset(iter, 0, sizeof(BMOIter));
1045
1046         iter->slot = slot;
1047         iter->cur = 0;
1048         iter->restrictmask = restrictmask;
1049
1050         if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1051                 if (iter->slot->data.ghash) {
1052                         BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1053                 }
1054                 else {
1055                         return NULL;
1056                 }
1057         }
1058
1059         return BMO_iter_step(iter);
1060 }
1061
1062 void *BMO_iter_step(BMOIter *iter)
1063 {
1064         if (iter->slot->slottype == BMO_OP_SLOT_ELEMENT_BUF) {
1065                 BMHeader *h;
1066
1067                 if (iter->cur >= iter->slot->len) {
1068                         return NULL;
1069                 }
1070
1071                 h = ((void **)iter->slot->data.buf)[iter->cur++];
1072                 while (!(iter->restrictmask & h->htype)) {
1073                         if (iter->cur >= iter->slot->len) {
1074                                 return NULL;
1075                         }
1076
1077                         h = ((void **)iter->slot->data.buf)[iter->cur++];
1078                 }
1079
1080                 return h;
1081         }
1082         else if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1083                 BMOElemMapping *map;
1084                 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1085                 map = BLI_ghashIterator_getValue(&iter->giter);
1086                 
1087                 iter->val = map + 1;
1088
1089                 BLI_ghashIterator_step(&iter->giter);
1090
1091                 return ret;
1092         }
1093
1094         return NULL;
1095 }
1096
1097 /* used for iterating over mapping */
1098 void *BMO_iter_map_value(BMOIter *iter)
1099 {
1100         return iter->val;
1101 }
1102
1103 void *BMO_iter_map_value_p(BMOIter *iter)
1104 {
1105         return *((void **)iter->val);
1106 }
1107
1108 float BMO_iter_map_value_f(BMOIter *iter)
1109 {
1110         return *((float *)iter->val);
1111 }
1112
1113 /* error syste */
1114 typedef struct BMOpError {
1115         struct BMOpError *next, *prev;
1116         int errorcode;
1117         BMOperator *op;
1118         const char *msg;
1119 } BMOpError;
1120
1121 void BMO_error_clear(BMesh *bm)
1122 {
1123         while (BMO_error_pop(bm, NULL, NULL));
1124 }
1125
1126 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1127 {
1128         BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1129         
1130         err->errorcode = errcode;
1131         if (!msg) msg = bmo_error_messages[errcode];
1132         err->msg = msg;
1133         err->op = owner;
1134         
1135         BLI_addhead(&bm->errorstack, err);
1136 }
1137
1138 int BMO_error_occurred(BMesh *bm)
1139 {
1140         return bm->errorstack.first != NULL;
1141 }
1142
1143 /* returns error code or 0 if no erro */
1144 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1145 {
1146         BMOpError *err = bm->errorstack.first;
1147         if (!err) {
1148                 return 0;
1149         }
1150
1151         if (msg) *msg = err->msg;
1152         if (op) *op = err->op;
1153         
1154         return err->errorcode;
1155 }
1156
1157 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1158 {
1159         int errorcode = BMO_error_get(bm, msg, op);
1160         
1161         if (errorcode) {
1162                 BMOpError *err = bm->errorstack.first;
1163                 
1164                 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1165                 MEM_freeN(err);
1166         }
1167
1168         return errorcode;
1169 }
1170
1171
1172 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1173
1174 static int bmo_name_to_slotcode(BMOpDefine *def, const char *name)
1175 {
1176         int i;
1177
1178         for (i = 0; def->slottypes[i].type; i++) {
1179                 if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
1180                         return i;
1181                 }
1182         }
1183
1184         return -1;
1185 }
1186
1187 static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name)
1188 {
1189         int i = bmo_name_to_slotcode(def, name);
1190         if (i < 0) {
1191                 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1192         }
1193
1194         return i;
1195 }
1196
1197 static int bmo_opname_to_opcode(const char *opname)
1198 {
1199         int i;
1200
1201         for (i = 0; i < bmesh_total_ops; i++) {
1202                 if (!strcmp(opname, opdefines[i]->name)) {
1203                         return i;
1204                 }
1205         }
1206
1207         fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1208         return -1;
1209 }
1210
1211 /* Example:
1212  * BMO_op_callf(bm, "del %i %hv", DEL_ONLYFACES, BM_ELEM_SELECT);
1213  *
1214  *  i - int
1215  *  b - boolean (same as int but 1/0 only)
1216  *  f - float
1217  *  hv - header flagged verts (hflag)
1218  *  he - header flagged edges (hflag)
1219  *  hf - header flagged faces (hflag)
1220  *  fv - flagged verts (oflag)
1221  *  fe - flagged edges (oflag)
1222  *  ff - flagged faces (oflag)
1223  */
1224
1225 int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1226 {
1227         BMOpDefine *def;
1228         char *opname, *ofmt, *fmt;
1229         char slotname[64] = {0};
1230         int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, ret, type, state;
1231         int noslot = 0;
1232
1233
1234         /* basic useful info to help find where bmop formatting strings fail */
1235         int lineno = -1;
1236 #   define GOTO_ERROR { lineno = __LINE__; goto error; }
1237
1238
1239         /* we muck around in here, so dup i */
1240         fmt = ofmt = BLI_strdup(_fmt);
1241         
1242         /* find operator nam */
1243         i = strcspn(fmt, " \t");
1244
1245         opname = fmt;
1246         if (!opname[i]) noslot = 1;
1247         opname[i] = '\0';
1248
1249         fmt += i + (noslot ? 0 : 1);
1250         
1251         i = bmo_opname_to_opcode(opname);
1252
1253         if (i == -1) {
1254                 MEM_freeN(ofmt);
1255                 return FALSE;
1256         }
1257
1258         BMO_op_init(bm, op, opname);
1259         def = opdefines[i];
1260         
1261         i = 0;
1262         state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1263
1264         while (*fmt) {
1265                 if (state) {
1266                         /* jump past leading whitespac */
1267                         i = strspn(fmt, " \t");
1268                         fmt += i;
1269                         
1270                         /* ignore trailing whitespac */
1271                         if (!fmt[i])
1272                                 break;
1273
1274                         /* find end of slot name.  currently this is
1275                          * a little flexible, allowing "slot=%f",
1276                          * "slot %f", "slot%f", and "slot\t%f". */
1277                         i = strcspn(fmt, "= \t%");
1278                         if (!fmt[i]) GOTO_ERROR;
1279
1280                         fmt[i] = 0;
1281
1282                         if (bmo_name_to_slotcode_check(def, fmt) < 0) GOTO_ERROR;
1283                         
1284                         BLI_strncpy(slotname, fmt, sizeof(slotname));
1285                         
1286                         state = 0;
1287                         fmt += i;
1288                 }
1289                 else {
1290                         switch (*fmt) {
1291                                 case ' ':
1292                                 case '\t':
1293                                 case '=':
1294                                 case '%':
1295                                         break;
1296                                 case 'm': {
1297                                         int size, c;
1298
1299                                         c = NEXT_CHAR(fmt);
1300                                         fmt++;
1301
1302                                         if (c == '3') size = 3;
1303                                         else if (c == '4') size = 4;
1304                                         else GOTO_ERROR;
1305
1306                                         BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
1307                                         state = 1;
1308                                         break;
1309                                 }
1310                                 case 'v': {
1311                                         BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
1312                                         state = 1;
1313                                         break;
1314                                 }
1315                                 case 'e': {
1316                                         BMHeader *ele = va_arg(vlist, void *);
1317                                         BMOpSlot *slot = BMO_slot_get(op, slotname);
1318
1319                                         slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1320                                         slot->len = 1;
1321                                         *((void **)slot->data.buf) = ele;
1322
1323                                         state = 1;
1324                                         break;
1325                                 }
1326                                 case 's': {
1327                                         BMOperator *op2 = va_arg(vlist, void *);
1328                                         const char *slotname2 = va_arg(vlist, char *);
1329
1330                                         BMO_slot_copy(op2, op, slotname2, slotname);
1331                                         state = 1;
1332                                         break;
1333                                 }
1334                                 case 'i':
1335                                         BMO_slot_int_set(op, slotname, va_arg(vlist, int));
1336                                         state = 1;
1337                                         break;
1338                                 case 'b':
1339                                         BMO_slot_bool_set(op, slotname, va_arg(vlist, int));
1340                                         state = 1;
1341                                         break;
1342                                 case 'p':
1343                                         BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
1344                                         state = 1;
1345                                         break;
1346                                 case 'f':
1347                                 case 'h':
1348                                 case 'a':
1349                                         type = *fmt;
1350
1351                                         if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\t' || NEXT_CHAR(fmt) == '\0') {
1352                                                 BMO_slot_float_set(op, slotname, va_arg(vlist, double));
1353                                         }
1354                                         else {
1355                                                 ret = 0;
1356                                                 stop = 0;
1357                                                 while (1) {
1358                                                         switch (NEXT_CHAR(fmt)) {
1359                                                                 case 'f': ret |= BM_FACE; break;
1360                                                                 case 'e': ret |= BM_EDGE; break;
1361                                                                 case 'v': ret |= BM_VERT; break;
1362                                                                 default:
1363                                                                         stop = 1;
1364                                                                         break;
1365                                                         }
1366                                                         if (stop) {
1367                                                                 break;
1368                                                         }
1369
1370                                                         fmt++;
1371                                                 }
1372
1373                                                 if (type == 'h') {
1374                                                         BMO_slot_from_hflag(bm, op, slotname, va_arg(vlist, int), ret);
1375                                                 }
1376                                                 else if (type == 'a') {
1377                                                         BMO_slot_from_all(bm, op, slotname, ret);
1378                                                 }
1379                                                 else {
1380                                                         BMO_slot_from_flag(bm, op, slotname, va_arg(vlist, int), ret);
1381                                                 }
1382                                         }
1383
1384                                         state = 1;
1385                                         break;
1386                                 default:
1387                                         fprintf(stderr,
1388                                                 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1389                                                 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1390                                         break;
1391                         }
1392                 }
1393                 fmt++;
1394         }
1395
1396         MEM_freeN(ofmt);
1397         return TRUE;
1398 error:
1399
1400         /* non urgent todo - explain exactly what is failing */
1401         fprintf(stderr,
1402                 "%s: error parsing formatting string, %d in '%s'\n    see - %s:%d\n",
1403                 __func__, (int)(fmt - ofmt), _fmt, __FILE__, lineno);
1404         MEM_freeN(ofmt);
1405
1406         BMO_op_finish(bm, op);
1407         return FALSE;
1408
1409 #undef GOTO_ERROR
1410
1411 }
1412
1413
1414 int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1415 {
1416         va_list list;
1417
1418         va_start(list, fmt);
1419         if (!BMO_op_vinitf(bm, op, fmt, list)) {
1420                 printf("%s: failed\n", __func__);
1421                 va_end(list);
1422                 return FALSE;
1423         }
1424         va_end(list);
1425
1426         return TRUE;
1427 }
1428
1429 int BMO_op_callf(BMesh *bm, const char *fmt, ...)
1430 {
1431         va_list list;
1432         BMOperator op;
1433
1434         va_start(list, fmt);
1435         if (!BMO_op_vinitf(bm, &op, fmt, list)) {
1436                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1437                 va_end(list);
1438                 return FALSE;
1439         }
1440
1441         BMO_op_exec(bm, &op);
1442         BMO_op_finish(bm, &op);
1443
1444         va_end(list);
1445         return TRUE;
1446 }