bmesh: be more strict with operator string formatting, no tabs and only accept slot...
[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 char htype, const short oflag)
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 char htype, const short oflag)
600 {
601         GHashIterator it;
602         BMOpSlot *slot = BMO_slot_get(op, slotname);
603         BMElemF *ele_f;
604
605         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
606
607         /* sanity check */
608         if (!slot->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 htype, const char hflag)
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 char htype, const short oflag)
734 {
735         BMIter elements;
736         BMOpSlot *slot = BMO_slot_get(op, slotname);
737         int totelement = BMO_mesh_flag_count(bm, htype, oflag), 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 htype, const char hflag, 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 htype, const char hflag, 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 char htype, const short oflag)
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 char htype, const short oflag)
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 */, type, state;
1249         char htype;
1250         int noslot = 0;
1251
1252
1253         /* basic useful info to help find where bmop formatting strings fail */
1254         const char *err_reason = "Unknown";
1255         int lineno = -1;
1256
1257 #define GOTO_ERROR(reason)   \
1258         {                        \
1259                 err_reason = reason; \
1260                 lineno = __LINE__;   \
1261                 goto error;          \
1262         } (void)0
1263
1264         /* we muck around in here, so dup i */
1265         fmt = ofmt = BLI_strdup(_fmt);
1266         
1267         /* find operator name */
1268         i = strcspn(fmt, " ");
1269
1270         opname = fmt;
1271         if (!opname[i]) noslot = 1;
1272         opname[i] = '\0';
1273
1274         fmt += i + (noslot ? 0 : 1);
1275         
1276         i = bmo_opname_to_opcode(opname);
1277
1278         if (i == -1) {
1279                 MEM_freeN(ofmt);
1280                 return FALSE;
1281         }
1282
1283         BMO_op_init(bm, op, opname);
1284         def = opdefines[i];
1285         
1286         i = 0;
1287         state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1288
1289         while (*fmt) {
1290                 if (state) {
1291                         /* jump past leading whitespac */
1292                         i = strspn(fmt, " ");
1293                         fmt += i;
1294                         
1295                         /* ignore trailing whitespac */
1296                         if (!fmt[i])
1297                                 break;
1298
1299                         /* find end of slot name, only "slot=%f", can be used */
1300                         i = strcspn(fmt, "=");
1301                         if (!fmt[i]) {
1302                                 GOTO_ERROR("could not match end of slot name");
1303                         }
1304
1305                         fmt[i] = 0;
1306
1307                         if (bmo_name_to_slotcode_check(def, fmt) < 0) {
1308                                 GOTO_ERROR("name to slot code check failed");
1309                         }
1310                         
1311                         BLI_strncpy(slotname, fmt, sizeof(slotname));
1312                         
1313                         state = 0;
1314                         fmt += i;
1315                 }
1316                 else {
1317                         switch (*fmt) {
1318                                 case ' ':
1319                                 case '=':
1320                                 case '%':
1321                                         break;
1322                                 case 'm': {
1323                                         int size, c;
1324
1325                                         c = NEXT_CHAR(fmt);
1326                                         fmt++;
1327
1328                                         if      (c == '3') size = 3;
1329                                         else if (c == '4') size = 4;
1330                                         else GOTO_ERROR("matrix size was not 3 or 4");
1331
1332                                         BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
1333                                         state = 1;
1334                                         break;
1335                                 }
1336                                 case 'v': {
1337                                         BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
1338                                         state = 1;
1339                                         break;
1340                                 }
1341                                 case 'e': {
1342                                         BMHeader *ele = va_arg(vlist, void *);
1343                                         BMOpSlot *slot = BMO_slot_get(op, slotname);
1344
1345                                         slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1346                                         slot->len = 1;
1347                                         *((void **)slot->data.buf) = ele;
1348
1349                                         state = 1;
1350                                         break;
1351                                 }
1352                                 case 's': {
1353                                         BMOperator *op2 = va_arg(vlist, void *);
1354                                         const char *slotname2 = va_arg(vlist, char *);
1355
1356                                         BMO_slot_copy(op2, op, slotname2, slotname);
1357                                         state = 1;
1358                                         break;
1359                                 }
1360                                 case 'i':
1361                                         BMO_slot_int_set(op, slotname, va_arg(vlist, int));
1362                                         state = 1;
1363                                         break;
1364                                 case 'b':
1365                                         BMO_slot_bool_set(op, slotname, va_arg(vlist, int));
1366                                         state = 1;
1367                                         break;
1368                                 case 'p':
1369                                         BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
1370                                         state = 1;
1371                                         break;
1372                                 case 'f':
1373                                 case 'h':
1374                                 case 'a':
1375                                         type = *fmt;
1376
1377                                         if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\0') {
1378                                                 BMO_slot_float_set(op, slotname, va_arg(vlist, double));
1379                                         }
1380                                         else {
1381                                                 htype = 0;
1382                                                 stop = 0;
1383                                                 while (1) {
1384                                                         switch (NEXT_CHAR(fmt)) {
1385                                                                 case 'f': htype |= BM_FACE; break;
1386                                                                 case 'e': htype |= BM_EDGE; break;
1387                                                                 case 'v': htype |= BM_VERT; break;
1388                                                                 default:
1389                                                                         stop = 1;
1390                                                                         break;
1391                                                         }
1392                                                         if (stop) {
1393                                                                 break;
1394                                                         }
1395
1396                                                         fmt++;
1397                                                 }
1398
1399                                                 if (type == 'h') {
1400                                                         BMO_slot_buffer_from_hflag(bm, op, slotname, htype, va_arg(vlist, int));
1401                                                 }
1402                                                 else if (type == 'a') {
1403                                                         BMO_slot_buffer_from_all(bm, op, slotname, htype);
1404                                                 }
1405                                                 else {
1406                                                         BMO_slot_buffer_from_flag(bm, op, slotname, htype, va_arg(vlist, int));
1407                                                 }
1408                                         }
1409
1410                                         state = 1;
1411                                         break;
1412                                 default:
1413                                         fprintf(stderr,
1414                                                 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1415                                                 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1416                                         break;
1417                         }
1418                 }
1419                 fmt++;
1420         }
1421
1422         MEM_freeN(ofmt);
1423         return TRUE;
1424 error:
1425
1426         /* non urgent todo - explain exactly what is failing */
1427         fprintf(stderr, "%s: error parsing formatting string\n", __func__);
1428
1429         fprintf(stderr, "string: '%s', position %d\n", _fmt, (int)(fmt - ofmt));
1430         fprintf(stderr, "         ");
1431         {
1432                 int pos = (int)(fmt - ofmt);
1433                 int i;
1434                 for (i = 0; i < pos; i++) {
1435                         fprintf(stderr, " ");
1436                 }
1437                 fprintf(stderr, "^\n");
1438         }
1439
1440         fprintf(stderr, "source code:  %s:%d\n", __FILE__, lineno);
1441
1442         fprintf(stderr, "reason: %s\n", err_reason);
1443
1444
1445         MEM_freeN(ofmt);
1446
1447         BMO_op_finish(bm, op);
1448         return FALSE;
1449
1450 #undef GOTO_ERROR
1451
1452 }
1453
1454
1455 int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1456 {
1457         va_list list;
1458
1459         va_start(list, fmt);
1460         if (!BMO_op_vinitf(bm, op, fmt, list)) {
1461                 printf("%s: failed\n", __func__);
1462                 va_end(list);
1463                 return FALSE;
1464         }
1465         va_end(list);
1466
1467         return TRUE;
1468 }
1469
1470 int BMO_op_callf(BMesh *bm, const char *fmt, ...)
1471 {
1472         va_list list;
1473         BMOperator op;
1474
1475         va_start(list, fmt);
1476         if (!BMO_op_vinitf(bm, &op, fmt, list)) {
1477                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1478                 va_end(list);
1479                 return FALSE;
1480         }
1481
1482         BMO_op_exec(bm, &op);
1483         BMO_op_finish(bm, &op);
1484
1485         va_end(list);
1486         return TRUE;
1487 }