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