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