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