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