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