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