fix [#30772] No more than two subdivions give correct result when adding an icosphere
[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, 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 have a
454  * specific flag enabled (or disabled if test_for_enabled is false).
455  *
456  */
457
458 static int bmo_mesh_flag_count(BMesh *bm, const char htype, const short oflag,
459                                const short test_for_enabled)
460 {
461         const char iter_types[3] = {BM_VERTS_OF_MESH,
462                                     BM_EDGES_OF_MESH,
463                                     BM_FACES_OF_MESH};
464
465         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
466
467         BMIter iter;
468         int count = 0;
469         BMElemF *ele_f;
470         int i;
471
472         BLI_assert(ELEM(TRUE, FALSE, test_for_enabled));
473
474         for (i = 0; i < 3; i++) {
475                 if (htype & flag_types[i]) {
476                         BM_ITER(ele_f, &iter, bm, iter_types[i], NULL) {
477                                 if (BMO_elem_flag_test_bool(bm, ele_f, oflag) == test_for_enabled)
478                                         count++;
479                         }
480                 }
481         }
482
483         return count;
484 }
485
486
487 int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag)
488 {
489         return bmo_mesh_flag_count(bm, htype, oflag, TRUE);
490 }
491
492 int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag)
493 {
494         return bmo_mesh_flag_count(bm, htype, oflag, FALSE);
495 }
496
497 void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
498 {
499         const char iter_types[3] = {BM_VERTS_OF_MESH,
500                                     BM_EDGES_OF_MESH,
501                                     BM_FACES_OF_MESH};
502
503         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
504
505         BMIter iter;
506         BMElemF *ele;
507         int i;
508
509         for (i = 0; i < 3; i++) {
510                 if (htype & flag_types[i]) {
511                         BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
512                                 BMO_elem_flag_disable(bm, ele, oflag);
513                         }
514                 }
515         }
516 }
517
518 int BMO_slot_buffer_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
519 {
520         BMOpSlot *slot = BMO_slot_get(op, slotname);
521         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
522         
523         /* check if its actually a buffer */
524         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
525                 return 0;
526
527         return slot->len;
528 }
529
530 int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
531 {
532         BMOpSlot *slot = BMO_slot_get(op, slotname);
533         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
534         
535         /* check if its actually a buffer */
536         if (!(slot->slottype == BMO_OP_SLOT_MAPPING))
537                 return 0;
538
539         return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
540 }
541
542 /* inserts a key/value mapping into a mapping slot.  note that it copies the
543  * value, it doesn't store a reference to it. */
544
545 void BMO_slot_map_insert(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
546                          void *element, void *data, int len)
547 {
548         BMOElemMapping *mapping;
549         BMOpSlot *slot = BMO_slot_get(op, slotname);
550         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
551
552         mapping = (BMOElemMapping *) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
553
554         mapping->element = (BMHeader *) element;
555         mapping->len = len;
556         memcpy(mapping + 1, data, len);
557
558         if (!slot->data.ghash) {
559                 slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh slot map hash");
560         }
561
562         BLI_ghash_insert(slot->data.ghash, element, mapping);
563 }
564
565 #if 0
566 void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slotcode, int totadd)
567 {
568         BMOpSlot *slot = &op->slots[slotcode];
569         void *tmp;
570         ssize_t allocsize;
571         
572         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
573
574         /* check if its actually a buffer */
575         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
576                 return NULL;
577
578         if (slot->flag & BMOS_DYNAMIC_ARRAY) {
579                 if (slot->len >= slot->size) {
580                         slot->size = (slot->size + 1 + totadd) * 2;
581
582                         allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size;
583
584                         tmp = slot->data.buf;
585                         slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
586                         memcpy(slot->data.buf, tmp, allocsize);
587                         MEM_freeN(tmp);
588                 }
589
590                 slot->len += totadd;
591         }
592         else {
593                 slot->flag |= BMOS_DYNAMIC_ARRAY;
594                 slot->len += totadd;
595                 slot->size = slot->len + 2;
596
597                 allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len;
598
599                 tmp = slot->data.buf;
600                 slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
601                 memcpy(slot->data.buf, tmp, allocsize);
602         }
603
604         return slot->data.buf;
605 }
606 #endif
607
608 void BMO_slot_map_to_flag(BMesh *bm, BMOperator *op, const char *slotname,
609                           const char htype, const short oflag)
610 {
611         GHashIterator it;
612         BMOpSlot *slot = BMO_slot_get(op, slotname);
613         BMElemF *ele_f;
614
615         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
616
617         /* sanity check */
618         if (!slot->data.ghash) return;
619
620         BLI_ghashIterator_init(&it, slot->data.ghash);
621         for ( ; (ele_f = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
622                 if (ele_f->head.htype & htype) {
623                         BMO_elem_flag_enable(bm, ele_f, oflag);
624                 }
625         }
626 }
627
628 static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slotname, int len)
629 {
630         BMOpSlot *slot = BMO_slot_get(op, slotname);
631         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
632
633         /* check if its actually a buffer */
634         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
635                 return NULL;
636         
637         slot->len = len;
638         if (len)
639                 slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slottype] * len);
640         return slot->data.buf;
641 }
642
643 /**
644  * \brief BMO_ALL_TO_SLOT
645  *
646  * Copies all elements of a certain type into an operator slot.
647  */
648 static void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
649 {
650         BMOpSlot *output = BMO_slot_get(op, slotname);
651         int totelement = 0, i = 0;
652         
653         if (htype & BM_VERT) totelement += bm->totvert;
654         if (htype & BM_EDGE) totelement += bm->totedge;
655         if (htype & BM_FACE) totelement += bm->totface;
656
657         if (totelement) {
658                 BMIter iter;
659                 BMHeader *ele;
660
661                 bmo_slot_buffer_alloc(op, slotname, totelement);
662
663                 /* TODO - collapse these loops into one */
664
665                 if (htype & BM_VERT) {
666                         BM_ITER(ele, &iter, bm, BM_VERTS_OF_MESH, NULL) {
667                                 ((BMHeader **)output->data.p)[i] = ele;
668                                 i++;
669                         }
670                 }
671
672                 if (htype & BM_EDGE) {
673                         BM_ITER(ele, &iter, bm, BM_EDGES_OF_MESH, NULL) {
674                                 ((BMHeader **)output->data.p)[i] = ele;
675                                 i++;
676                         }
677                 }
678
679                 if (htype & BM_FACE) {
680                         BM_ITER(ele, &iter, bm, BM_FACES_OF_MESH, NULL) {
681                                 ((BMHeader **)output->data.p)[i] = ele;
682                                 i++;
683                         }
684                 }
685         }
686 }
687
688 /**
689  * \brief BMO_HEADERFLAG_TO_SLOT
690  *
691  * Copies elements of a certain type, which have a certain header flag
692  * enabled/disabled into a slot for an operator.
693  */
694 static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, const char *slotname,
695                                        const char htype, const char hflag,
696                                        const short test_for_enabled)
697 {
698         BMOpSlot *output = BMO_slot_get(op, slotname);
699         int totelement = 0, i = 0;
700
701         BLI_assert(ELEM(TRUE, FALSE, test_for_enabled));
702
703         if (test_for_enabled)
704                 totelement = BM_mesh_enabled_flag_count(bm, htype, hflag, TRUE);
705         else
706                 totelement = BM_mesh_disabled_flag_count(bm, htype, hflag, TRUE);
707
708         if (totelement) {
709                 BMIter iter;
710                 BMElem *ele;
711
712                 bmo_slot_buffer_alloc(op, slotname, totelement);
713
714                 /* TODO - collapse these loops into one */
715
716                 if (htype & BM_VERT) {
717                         BM_ITER(ele, &iter, bm, BM_VERTS_OF_MESH, NULL) {
718                                 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
719                                     BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
720                                 {
721                                         ((BMElem **)output->data.p)[i] = ele;
722                                         i++;
723                                 }
724                         }
725                 }
726
727                 if (htype & BM_EDGE) {
728                         BM_ITER(ele, &iter, bm, BM_EDGES_OF_MESH, NULL) {
729                                 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
730                                     BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
731                                 {
732                                         ((BMElem **)output->data.p)[i] = ele;
733                                         i++;
734                                 }
735                         }
736                 }
737
738                 if (htype & BM_FACE) {
739                         BM_ITER(ele, &iter, bm, BM_FACES_OF_MESH, NULL) {
740                                 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
741                                     BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
742                                 {
743                                         ((BMElem **)output->data.p)[i] = ele;
744                                         i++;
745                                 }
746                         }
747                 }
748         }
749         else {
750                 output->len = 0;
751         }
752 }
753
754 void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op, const char *slotname,
755                                         const char htype, const char hflag)
756 {
757         bmo_slot_buffer_from_hflag(bm, op, slotname, htype, hflag, TRUE);
758 }
759
760 void BMO_slot_buffer_from_disabled_hflag(BMesh *bm, BMOperator *op, const char *slotname,
761                                          const char htype, const char hflag)
762 {
763         bmo_slot_buffer_from_hflag(bm, op, slotname, htype, hflag, FALSE);
764 }
765
766 /**
767  * Copies the values from another slot to the end of the output slot.
768  */
769 void BMO_slot_buffer_append(BMOperator *output_op, const char *output_slot_name,
770                             BMOperator *other_op, const char *other_slot_name)
771 {
772         BMOpSlot *output_slot = BMO_slot_get(output_op, output_slot_name);
773         BMOpSlot *other_slot = BMO_slot_get(other_op, other_slot_name);
774
775         BLI_assert(output_slot->slottype == BMO_OP_SLOT_ELEMENT_BUF &&
776                    other_slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
777
778         if (output_slot->len == 0) {
779                 /* output slot is empty, copy rather than append */
780                 BMO_slot_copy(other_op, output_op, other_slot_name, output_slot_name);
781         }
782         else if (other_slot->len != 0) {
783                 int elem_size = BMO_OPSLOT_TYPEINFO[output_slot->slottype];
784                 int alloc_size = elem_size * (output_slot->len + other_slot->len);
785                 /* allocate new buffer */
786                 void *buf = BLI_memarena_alloc(output_op->arena, alloc_size);
787
788                 /* copy slot data */
789                 memcpy(buf, output_slot->data.buf, elem_size * output_slot->len);
790                 memcpy(((char *)buf) + elem_size * output_slot->len, other_slot->data.buf, elem_size * other_slot->len);
791
792                 output_slot->data.buf = buf;
793                 output_slot->len += other_slot->len;
794         }
795 }
796
797 /**
798  * \brief BMO_FLAG_TO_SLOT
799  *
800  * Copies elements of a certain type, which have a certain flag set
801  * into an output slot for an operator.
802  */
803 static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op, const char *slotname,
804                                       const char htype, const short oflag,
805                                       const short test_for_enabled)
806 {
807         BMOpSlot *slot = BMO_slot_get(op, slotname);
808         int totelement, i = 0;
809
810         BLI_assert(ELEM(TRUE, FALSE, test_for_enabled));
811
812         if (test_for_enabled)
813                 totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag);
814         else
815                 totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag);
816
817         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
818
819         if (totelement) {
820                 BMIter iter;
821                 BMHeader *ele;
822                 BMHeader **ele_array;
823
824                 bmo_slot_buffer_alloc(op, slotname, totelement);
825
826                 ele_array = (BMHeader **)slot->data.p;
827
828                 /* TODO - collapse these loops into one */
829
830                 if (htype & BM_VERT) {
831                         BM_ITER(ele, &iter, bm, BM_VERTS_OF_MESH, NULL) {
832                                 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
833                                         ele_array[i] = ele;
834                                         i++;
835                                 }
836                         }
837                 }
838
839                 if (htype & BM_EDGE) {
840                         BM_ITER(ele, &iter, bm, BM_EDGES_OF_MESH, NULL) {
841                                 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
842                                         ele_array[i] = ele;
843                                         i++;
844                                 }
845                         }
846                 }
847
848                 if (htype & BM_FACE) {
849                         BM_ITER(ele, &iter, bm, BM_FACES_OF_MESH, NULL) {
850                                 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
851                                         ele_array[i] = ele;
852                                         i++;
853                                 }
854                         }
855                 }
856         }
857         else {
858                 slot->len = 0;
859         }
860 }
861
862 void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, const char *slotname,
863                                        const char htype, const short oflag)
864 {
865         bmo_slot_buffer_from_flag(bm, op, slotname, htype, oflag, TRUE);
866 }
867
868 void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op, const char *slotname,
869                                         const char htype, const short oflag)
870 {
871         bmo_slot_buffer_from_flag(bm, op, slotname, htype, oflag, FALSE);
872 }
873
874 /**
875  * \brief BMO_FLAG_BUFFER
876  *
877  * Header Flags elements in a slots buffer, automatically
878  * using the selection API where appropriate.
879  */
880 void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slotname,
881                                   const char htype, const char hflag, const char do_flush)
882 {
883         BMOpSlot *slot = BMO_slot_get(op, slotname);
884         BMElem **data =  slot->data.p;
885         int i;
886         const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
887         const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
888
889         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
890
891         for (i = 0; i < slot->len; i++, data++) {
892                 if (!(htype & (*data)->head.htype))
893                         continue;
894
895                 if (do_flush_select) {
896                         BM_elem_select_set(bm, *data, TRUE);
897                 }
898
899                 if (do_flush_hide) {
900                         BM_elem_hide_set(bm, *data, FALSE);
901                 }
902
903                 BM_elem_flag_enable(*data, hflag);
904         }
905 }
906
907 /**
908  * \brief BMO_FLAG_BUFFER
909  *
910  * Removes flags from elements in a slots buffer, automatically
911  * using the selection API where appropriate.
912  */
913 void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slotname,
914                                    const char htype, const char hflag, const char do_flush)
915 {
916         BMOpSlot *slot = BMO_slot_get(op, slotname);
917         BMElem **data =  slot->data.p;
918         int i;
919         const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
920         const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
921
922         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
923
924         for (i = 0; i < slot->len; i++, data++) {
925                 if (!(htype & (*data)->head.htype))
926                         continue;
927
928                 if (do_flush_select) {
929                         BM_elem_select_set(bm, *data, FALSE);
930                 }
931
932                 if (do_flush_hide) {
933                         BM_elem_hide_set(bm, *data, FALSE);
934                 }
935
936                 BM_elem_flag_disable(*data, hflag);
937         }
938 }
939
940 int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
941 {
942         int count = 0;
943
944         if (v->e) {
945                 BMEdge *curedge;
946                 const int len = bmesh_disk_count(v);
947                 int i;
948                 
949                 for (i = 0, curedge = v->e; i < len; i++) {
950                         if (BMO_elem_flag_test(bm, curedge, oflag))
951                                 count++;
952                         curedge = bmesh_disk_edge_next(curedge, v);
953                 }
954         }
955
956         return count;
957 }
958
959 /**
960  * \brief BMO_FLAG_BUFFER
961  *
962  * Flags elements in a slots buffer
963  */
964 void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slotname,
965                                  const char htype, const short oflag)
966 {
967         BMOpSlot *slot = BMO_slot_get(op, slotname);
968         BMHeader **data =  slot->data.p;
969         int i;
970
971         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
972
973         for (i = 0; i < slot->len; i++) {
974                 if (!(htype & data[i]->htype))
975                         continue;
976
977                 BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
978         }
979 }
980
981 /**
982  * \brief BMO_FLAG_BUFFER
983  *
984  * Removes flags from elements in a slots buffer
985  */
986 void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slotname,
987                                   const char htype, const short oflag)
988 {
989         BMOpSlot *slot = BMO_slot_get(op, slotname);
990         BMHeader **data =  slot->data.p;
991         int i;
992
993         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
994
995         for (i = 0; i < slot->len; i++) {
996                 if (!(htype & data[i]->htype))
997                         continue;
998
999                 BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
1000         }
1001 }
1002
1003
1004 /**
1005  * \brief ALLOC/FREE FLAG LAYER
1006  *
1007  * Used by operator stack to free/allocate
1008  * private flag data. This is allocated
1009  * using a mempool so the allocation/frees
1010  * should be quite fast.
1011  *
1012  * BMESH_TODO:
1013  * Investigate not freeing flag layers until
1014  * all operators have been executed. This would
1015  * save a lot of realloc potentially.
1016  */
1017 static void bmo_flag_layer_alloc(BMesh *bm)
1018 {
1019         BMElemF *ele;
1020         /* set the index values since we are looping over all data anyway,
1021          * may save time later on */
1022         int i;
1023
1024         BMIter iter;
1025         BLI_mempool *oldpool = bm->toolflagpool;                /* old flag pool */
1026         BLI_mempool *newpool;
1027         void *oldflags;
1028
1029         /* store memcpy size for reuse */
1030         const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
1031         
1032         bm->totflags++;
1033
1034         /* allocate new flag poo */
1035         bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, 512, 512, 0);
1036         
1037         /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
1038         BM_ITER_INDEX(ele, &iter, bm, BM_VERTS_OF_MESH, NULL, i) {
1039                 oldflags = ele->oflags;
1040                 ele->oflags = BLI_mempool_calloc(newpool);
1041                 memcpy(ele->oflags, oldflags, old_totflags_size);
1042                 BM_elem_index_set(ele, i); /* set_inline */
1043         }
1044         BM_ITER_INDEX(ele, &iter, bm, BM_EDGES_OF_MESH, NULL, i) {
1045                 oldflags = ele->oflags;
1046                 ele->oflags = BLI_mempool_calloc(newpool);
1047                 memcpy(ele->oflags, oldflags, old_totflags_size);
1048                 BM_elem_index_set(ele, i); /* set_inline */
1049         }
1050         BM_ITER_INDEX(ele, &iter, bm, BM_FACES_OF_MESH, NULL, i) {
1051                 oldflags = ele->oflags;
1052                 ele->oflags = BLI_mempool_calloc(newpool);
1053                 memcpy(ele->oflags, oldflags, old_totflags_size);
1054                 BM_elem_index_set(ele, i); /* set_inline */
1055         }
1056
1057         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1058
1059         BLI_mempool_destroy(oldpool);
1060 }
1061
1062 static void bmo_flag_layer_free(BMesh *bm)
1063 {
1064         BMElemF *ele;
1065         /* set the index values since we are looping over all data anyway,
1066          * may save time later on */
1067         int i;
1068
1069         BMIter iter;
1070         BLI_mempool *oldpool = bm->toolflagpool;
1071         BLI_mempool *newpool;
1072         void *oldflags;
1073         
1074         /* store memcpy size for reuse */
1075         const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
1076
1077         /* de-increment the totflags first.. */
1078         bm->totflags--;
1079         /* allocate new flag poo */
1080         bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, BLI_MEMPOOL_SYSMALLOC);
1081         
1082         /* now go through and memcpy all the flag */
1083         BM_ITER_INDEX(ele, &iter, bm, BM_VERTS_OF_MESH, NULL, i) {
1084                 oldflags = ele->oflags;
1085                 ele->oflags = BLI_mempool_calloc(newpool);
1086                 memcpy(ele->oflags, oldflags, new_totflags_size);
1087                 BM_elem_index_set(ele, i); /* set_inline */
1088         }
1089         BM_ITER_INDEX(ele, &iter, bm, BM_EDGES_OF_MESH, NULL, i) {
1090                 oldflags = ele->oflags;
1091                 ele->oflags = BLI_mempool_calloc(newpool);
1092                 memcpy(ele->oflags, oldflags, new_totflags_size);
1093                 BM_elem_index_set(ele, i); /* set_inline */
1094         }
1095         BM_ITER_INDEX(ele, &iter, bm, BM_FACES_OF_MESH, NULL, i) {
1096                 oldflags = ele->oflags;
1097                 ele->oflags = BLI_mempool_calloc(newpool);
1098                 memcpy(ele->oflags, oldflags, new_totflags_size);
1099                 BM_elem_index_set(ele, i); /* set_inline */
1100         }
1101
1102         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1103
1104         BLI_mempool_destroy(oldpool);
1105 }
1106
1107 static void bmo_flag_layer_clear(BMesh *bm)
1108 {
1109         BMElemF *ele;
1110         /* set the index values since we are looping over all data anyway,
1111          * may save time later on */
1112         int i;
1113
1114         BMIter iter;
1115         const int totflags_offset = bm->totflags - 1;
1116
1117         /* now go through and memcpy all the flag */
1118         BM_ITER_INDEX(ele, &iter, bm, BM_VERTS_OF_MESH, NULL, i) {
1119                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1120                 BM_elem_index_set(ele, i); /* set_inline */
1121         }
1122         BM_ITER_INDEX(ele, &iter, bm, BM_EDGES_OF_MESH, NULL, i) {
1123                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1124                 BM_elem_index_set(ele, i); /* set_inline */
1125         }
1126         BM_ITER_INDEX(ele, &iter, bm, BM_FACES_OF_MESH, NULL, i) {
1127                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1128                 BM_elem_index_set(ele, i); /* set_inline */
1129         }
1130
1131         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1132 }
1133
1134 void *BMO_slot_buffer_elem_first(BMOperator *op, const char *slotname)
1135 {
1136         BMOpSlot *slot = BMO_slot_get(op, slotname);
1137         
1138         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
1139                 return NULL;
1140
1141         return slot->data.buf ? *(void **)slot->data.buf : NULL;
1142 }
1143
1144 /**
1145  * \brief New Iterator
1146  *
1147  * \param restrictmask restricts the iteration to certain element types
1148  * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
1149  * over an element buffer (not a mapping). */
1150 void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
1151                    const char *slotname, const char restrictmask)
1152 {
1153         BMOpSlot *slot = BMO_slot_get(op, slotname);
1154
1155         memset(iter, 0, sizeof(BMOIter));
1156
1157         iter->slot = slot;
1158         iter->cur = 0;
1159         iter->restrictmask = restrictmask;
1160
1161         if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1162                 if (iter->slot->data.ghash) {
1163                         BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1164                 }
1165                 else {
1166                         return NULL;
1167                 }
1168         }
1169
1170         return BMO_iter_step(iter);
1171 }
1172
1173 void *BMO_iter_step(BMOIter *iter)
1174 {
1175         if (iter->slot->slottype == BMO_OP_SLOT_ELEMENT_BUF) {
1176                 BMHeader *h;
1177
1178                 if (iter->cur >= iter->slot->len) {
1179                         return NULL;
1180                 }
1181
1182                 h = ((void **)iter->slot->data.buf)[iter->cur++];
1183                 while (!(iter->restrictmask & h->htype)) {
1184                         if (iter->cur >= iter->slot->len) {
1185                                 return NULL;
1186                         }
1187
1188                         h = ((void **)iter->slot->data.buf)[iter->cur++];
1189                 }
1190
1191                 return h;
1192         }
1193         else if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1194                 BMOElemMapping *map;
1195                 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1196                 map = BLI_ghashIterator_getValue(&iter->giter);
1197                 
1198                 iter->val = map + 1;
1199
1200                 BLI_ghashIterator_step(&iter->giter);
1201
1202                 return ret;
1203         }
1204
1205         return NULL;
1206 }
1207
1208 /* used for iterating over mapping */
1209 void *BMO_iter_map_value(BMOIter *iter)
1210 {
1211         return iter->val;
1212 }
1213
1214 void *BMO_iter_map_value_p(BMOIter *iter)
1215 {
1216         return *((void **)iter->val);
1217 }
1218
1219 float BMO_iter_map_value_f(BMOIter *iter)
1220 {
1221         return *((float *)iter->val);
1222 }
1223
1224 /* error syste */
1225 typedef struct BMOpError {
1226         struct BMOpError *next, *prev;
1227         int errorcode;
1228         BMOperator *op;
1229         const char *msg;
1230 } BMOpError;
1231
1232 void BMO_error_clear(BMesh *bm)
1233 {
1234         while (BMO_error_pop(bm, NULL, NULL));
1235 }
1236
1237 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1238 {
1239         BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1240         
1241         err->errorcode = errcode;
1242         if (!msg) msg = bmo_error_messages[errcode];
1243         err->msg = msg;
1244         err->op = owner;
1245         
1246         BLI_addhead(&bm->errorstack, err);
1247 }
1248
1249 int BMO_error_occurred(BMesh *bm)
1250 {
1251         return bm->errorstack.first != NULL;
1252 }
1253
1254 /* returns error code or 0 if no erro */
1255 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1256 {
1257         BMOpError *err = bm->errorstack.first;
1258         if (!err) {
1259                 return 0;
1260         }
1261
1262         if (msg) *msg = err->msg;
1263         if (op) *op = err->op;
1264         
1265         return err->errorcode;
1266 }
1267
1268 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1269 {
1270         int errorcode = BMO_error_get(bm, msg, op);
1271         
1272         if (errorcode) {
1273                 BMOpError *err = bm->errorstack.first;
1274                 
1275                 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1276                 MEM_freeN(err);
1277         }
1278
1279         return errorcode;
1280 }
1281
1282
1283 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1284
1285 static int bmo_name_to_slotcode(BMOpDefine *def, const char *name)
1286 {
1287         int i;
1288
1289         for (i = 0; def->slottypes[i].type; i++) {
1290                 if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
1291                         return i;
1292                 }
1293         }
1294
1295         return -1;
1296 }
1297
1298 static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name)
1299 {
1300         int i = bmo_name_to_slotcode(def, name);
1301         if (i < 0) {
1302                 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1303         }
1304
1305         return i;
1306 }
1307
1308 static int bmo_opname_to_opcode(const char *opname)
1309 {
1310         int i;
1311
1312         for (i = 0; i < bmesh_total_ops; i++) {
1313                 if (!strcmp(opname, opdefines[i]->name)) {
1314                         return i;
1315                 }
1316         }
1317
1318         fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1319         return -1;
1320 }
1321
1322 /* Example:
1323  * BMO_op_callf(bm, "del %i %hv", DEL_ONLYFACES, BM_ELEM_SELECT);
1324  *
1325  *  i - int
1326  *  b - boolean (same as int but 1/0 only)
1327  *  f - float
1328  *  hv - header flagged verts (hflag)
1329  *  he - header flagged edges (hflag)
1330  *  hf - header flagged faces (hflag)
1331  *  fv - flagged verts (oflag)
1332  *  fe - flagged edges (oflag)
1333  *  ff - flagged faces (oflag)
1334  */
1335
1336 int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1337 {
1338         BMOpDefine *def;
1339         char *opname, *ofmt, *fmt;
1340         char slotname[64] = {0};
1341         int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, type, state;
1342         char htype;
1343         int noslot = 0;
1344
1345
1346         /* basic useful info to help find where bmop formatting strings fail */
1347         const char *err_reason = "Unknown";
1348         int lineno = -1;
1349
1350 #define GOTO_ERROR(reason)   \
1351         {                        \
1352                 err_reason = reason; \
1353                 lineno = __LINE__;   \
1354                 goto error;          \
1355         } (void)0
1356
1357         /* we muck around in here, so dup i */
1358         fmt = ofmt = BLI_strdup(_fmt);
1359         
1360         /* find operator name */
1361         i = strcspn(fmt, " ");
1362
1363         opname = fmt;
1364         if (!opname[i]) noslot = 1;
1365         opname[i] = '\0';
1366
1367         fmt += i + (noslot ? 0 : 1);
1368         
1369         i = bmo_opname_to_opcode(opname);
1370
1371         if (i == -1) {
1372                 MEM_freeN(ofmt);
1373                 return FALSE;
1374         }
1375
1376         BMO_op_init(bm, op, opname);
1377         def = opdefines[i];
1378         
1379         i = 0;
1380         state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1381
1382         while (*fmt) {
1383                 if (state) {
1384                         /* jump past leading whitespac */
1385                         i = strspn(fmt, " ");
1386                         fmt += i;
1387                         
1388                         /* ignore trailing whitespac */
1389                         if (!fmt[i])
1390                                 break;
1391
1392                         /* find end of slot name, only "slot=%f", can be used */
1393                         i = strcspn(fmt, "=");
1394                         if (!fmt[i]) {
1395                                 GOTO_ERROR("could not match end of slot name");
1396                         }
1397
1398                         fmt[i] = 0;
1399
1400                         if (bmo_name_to_slotcode_check(def, fmt) < 0) {
1401                                 GOTO_ERROR("name to slot code check failed");
1402                         }
1403                         
1404                         BLI_strncpy(slotname, fmt, sizeof(slotname));
1405                         
1406                         state = 0;
1407                         fmt += i;
1408                 }
1409                 else {
1410                         switch (*fmt) {
1411                                 case ' ':
1412                                 case '=':
1413                                 case '%':
1414                                         break;
1415                                 case 'm': {
1416                                         int size, c;
1417
1418                                         c = NEXT_CHAR(fmt);
1419                                         fmt++;
1420
1421                                         if      (c == '3') size = 3;
1422                                         else if (c == '4') size = 4;
1423                                         else GOTO_ERROR("matrix size was not 3 or 4");
1424
1425                                         BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
1426                                         state = 1;
1427                                         break;
1428                                 }
1429                                 case 'v': {
1430                                         BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
1431                                         state = 1;
1432                                         break;
1433                                 }
1434                                 case 'e': {
1435                                         BMHeader *ele = va_arg(vlist, void *);
1436                                         BMOpSlot *slot = BMO_slot_get(op, slotname);
1437
1438                                         slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1439                                         slot->len = 1;
1440                                         *((void **)slot->data.buf) = ele;
1441
1442                                         state = 1;
1443                                         break;
1444                                 }
1445                                 case 's': {
1446                                         BMOperator *op2 = va_arg(vlist, void *);
1447                                         const char *slotname2 = va_arg(vlist, char *);
1448
1449                                         BMO_slot_copy(op2, op, slotname2, slotname);
1450                                         state = 1;
1451                                         break;
1452                                 }
1453                                 case 'i':
1454                                         BMO_slot_int_set(op, slotname, va_arg(vlist, int));
1455                                         state = 1;
1456                                         break;
1457                                 case 'b':
1458                                         BMO_slot_bool_set(op, slotname, va_arg(vlist, int));
1459                                         state = 1;
1460                                         break;
1461                                 case 'p':
1462                                         BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
1463                                         state = 1;
1464                                         break;
1465                                 case 'f':
1466                                 case 'F':
1467                                 case 'h':
1468                                 case 'H':
1469                                 case 'a':
1470                                         type = *fmt;
1471
1472                                         if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\0') {
1473                                                 BMO_slot_float_set(op, slotname, va_arg(vlist, double));
1474                                         }
1475                                         else {
1476                                                 htype = 0;
1477                                                 stop = 0;
1478                                                 while (1) {
1479                                                         switch (NEXT_CHAR(fmt)) {
1480                                                                 case 'f': htype |= BM_FACE; break;
1481                                                                 case 'e': htype |= BM_EDGE; break;
1482                                                                 case 'v': htype |= BM_VERT; break;
1483                                                                 default:
1484                                                                         stop = 1;
1485                                                                         break;
1486                                                         }
1487                                                         if (stop) {
1488                                                                 break;
1489                                                         }
1490
1491                                                         fmt++;
1492                                                 }
1493
1494                                                 if (type == 'h') {
1495                                                         BMO_slot_buffer_from_enabled_hflag(bm, op, slotname, htype, va_arg(vlist, int));
1496                                                 }
1497                                                 else if (type == 'H') {
1498                                                         BMO_slot_buffer_from_disabled_hflag(bm, op, slotname, htype, va_arg(vlist, int));
1499                                                 }
1500                                                 else if (type == 'a') {
1501                                                         BMO_slot_buffer_from_all(bm, op, slotname, htype);
1502                                                 }
1503                                                 else if (type == 'f') {
1504                                                         BMO_slot_buffer_from_enabled_flag(bm, op, slotname, htype, va_arg(vlist, int));
1505                                                 }
1506                                                 else if (type == 'F') {
1507                                                         BMO_slot_buffer_from_disabled_flag(bm, op, slotname, htype, va_arg(vlist, int));
1508                                                 }
1509                                         }
1510
1511                                         state = 1;
1512                                         break;
1513                                 default:
1514                                         fprintf(stderr,
1515                                                 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1516                                                 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1517                                         break;
1518                         }
1519                 }
1520                 fmt++;
1521         }
1522
1523         MEM_freeN(ofmt);
1524         return TRUE;
1525 error:
1526
1527         /* non urgent todo - explain exactly what is failing */
1528         fprintf(stderr, "%s: error parsing formatting string\n", __func__);
1529
1530         fprintf(stderr, "string: '%s', position %d\n", _fmt, (int)(fmt - ofmt));
1531         fprintf(stderr, "         ");
1532         {
1533                 int pos = (int)(fmt - ofmt);
1534                 int i;
1535                 for (i = 0; i < pos; i++) {
1536                         fprintf(stderr, " ");
1537                 }
1538                 fprintf(stderr, "^\n");
1539         }
1540
1541         fprintf(stderr, "source code:  %s:%d\n", __FILE__, lineno);
1542
1543         fprintf(stderr, "reason: %s\n", err_reason);
1544
1545
1546         MEM_freeN(ofmt);
1547
1548         BMO_op_finish(bm, op);
1549         return FALSE;
1550
1551 #undef GOTO_ERROR
1552
1553 }
1554
1555
1556 int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1557 {
1558         va_list list;
1559
1560         va_start(list, fmt);
1561         if (!BMO_op_vinitf(bm, op, fmt, list)) {
1562                 printf("%s: failed\n", __func__);
1563                 va_end(list);
1564                 return FALSE;
1565         }
1566         va_end(list);
1567
1568         return TRUE;
1569 }
1570
1571 int BMO_op_callf(BMesh *bm, const char *fmt, ...)
1572 {
1573         va_list list;
1574         BMOperator op;
1575
1576         va_start(list, fmt);
1577         if (!BMO_op_vinitf(bm, &op, fmt, list)) {
1578                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1579                 va_end(list);
1580                 return FALSE;
1581         }
1582
1583         BMO_op_exec(bm, &op);
1584         BMO_op_finish(bm, &op);
1585
1586         va_end(list);
1587         return TRUE;
1588 }