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