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