bmesh toolflags would use BLI_MEMPOOL_SYSMALLOC when reducing layers only (would...
[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                 return 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 void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele)
871 {
872         BMO_ASSERT_SLOT_IN_OP(slot, op);
873         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
874         BLI_assert(slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE);
875         BLI_assert(slot->len == 0 || slot->len == 1);
876
877         BLI_assert(slot->slot_subtype.elem & ele->htype);
878
879         slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);  /* XXX, why 'x4' ? */
880         slot->len = 1;
881         *slot->data.buf = ele;
882 }
883
884 void *BMO_slot_buffer_get_single(BMOpSlot *slot)
885 {
886         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
887         BLI_assert(slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE);
888         BLI_assert(slot->len == 0 || slot->len == 1);
889
890         return slot->len ? (BMHeader *)slot->data.buf[0] : NULL;
891 }
892
893 /**
894  * Copies the values from another slot to the end of the output slot.
895  */
896 void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
897                              BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
898                              struct MemArena *arena_dst)
899 {
900         BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
901         BMOpSlot *slot_src  = BMO_slot_get(slot_args_src,  slot_name_src);
902
903         BLI_assert(slot_dst->slot_type == BMO_OP_SLOT_ELEMENT_BUF &&
904                    slot_src->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
905
906         if (slot_dst->len == 0) {
907                 /* output slot is empty, copy rather than append */
908                 _bmo_slot_copy(slot_args_src, slot_name_src,
909                                slot_args_dst, slot_name_dst,
910                                arena_dst);
911         }
912         else if (slot_src->len != 0) {
913                 int elem_size = BMO_OPSLOT_TYPEINFO[slot_dst->slot_type];
914                 int alloc_size = elem_size * (slot_dst->len + slot_src->len);
915                 /* allocate new buffer */
916                 void *buf = BLI_memarena_alloc(arena_dst, alloc_size);
917
918                 /* copy slot data */
919                 memcpy(buf, slot_dst->data.buf, elem_size * slot_dst->len);
920                 memcpy(((char *)buf) + elem_size * slot_dst->len, slot_src->data.buf, elem_size * slot_src->len);
921
922                 slot_dst->data.buf = buf;
923                 slot_dst->len += slot_src->len;
924         }
925 }
926
927 /**
928  * \brief BMO_FLAG_TO_SLOT
929  *
930  * Copies elements of a certain type, which have a certain flag set
931  * into an output slot for an operator.
932  */
933 static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op,
934                                       BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
935                                       const char htype, const short oflag,
936                                       const short test_for_enabled)
937 {
938         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
939         int totelement, i = 0;
940
941         BLI_assert(op->slots_in == slot_args || op->slots_out == slot_args);
942         BLI_assert(ELEM(TRUE, FALSE, test_for_enabled));
943
944         if (test_for_enabled)
945                 totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag);
946         else
947                 totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag);
948
949         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
950         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
951
952         if (totelement) {
953                 BMIter iter;
954                 BMHeader *ele;
955                 BMHeader **ele_array;
956
957                 BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
958
959                 ele_array = (BMHeader **)slot->data.buf;
960
961                 /* TODO - collapse these loops into one */
962
963                 if (htype & BM_VERT) {
964                         BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
965                                 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
966                                         ele_array[i] = ele;
967                                         i++;
968                                 }
969                         }
970                 }
971
972                 if (htype & BM_EDGE) {
973                         BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
974                                 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
975                                         ele_array[i] = ele;
976                                         i++;
977                                 }
978                         }
979                 }
980
981                 if (htype & BM_FACE) {
982                         BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
983                                 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
984                                         ele_array[i] = ele;
985                                         i++;
986                                 }
987                         }
988                 }
989         }
990         else {
991                 slot->len = 0;
992         }
993 }
994
995 void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op,
996                                        BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
997                                        const char htype, const short oflag)
998 {
999         bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, TRUE);
1000 }
1001
1002 void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op,
1003                                         BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1004                                         const char htype, const short oflag)
1005 {
1006         bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, FALSE);
1007 }
1008
1009 /**
1010  * \brief BMO_FLAG_BUFFER
1011  *
1012  * Header Flags elements in a slots buffer, automatically
1013  * using the selection API where appropriate.
1014  */
1015 void BMO_slot_buffer_hflag_enable(BMesh *bm,
1016                                   BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1017                                   const char htype, const char hflag, const char do_flush)
1018 {
1019         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1020         BMElem **data =  (BMElem **)slot->data.buf;
1021         int i;
1022         const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
1023         const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
1024
1025         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1026         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1027
1028         for (i = 0; i < slot->len; i++, data++) {
1029                 if (!(htype & (*data)->head.htype))
1030                         continue;
1031
1032                 if (do_flush_select) {
1033                         BM_elem_select_set(bm, *data, TRUE);
1034                 }
1035
1036                 if (do_flush_hide) {
1037                         BM_elem_hide_set(bm, *data, FALSE);
1038                 }
1039
1040                 BM_elem_flag_enable(*data, hflag);
1041         }
1042 }
1043
1044 /**
1045  * \brief BMO_FLAG_BUFFER
1046  *
1047  * Removes flags from elements in a slots buffer, automatically
1048  * using the selection API where appropriate.
1049  */
1050 void BMO_slot_buffer_hflag_disable(BMesh *bm,
1051                                    BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1052                                    const char htype, const char hflag, const char do_flush)
1053 {
1054         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1055         BMElem **data =  (BMElem **)slot->data.buf;
1056         int i;
1057         const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
1058         const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
1059
1060         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1061         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1062
1063         for (i = 0; i < slot->len; i++, data++) {
1064                 if (!(htype & (*data)->head.htype))
1065                         continue;
1066
1067                 if (do_flush_select) {
1068                         BM_elem_select_set(bm, *data, FALSE);
1069                 }
1070
1071                 if (do_flush_hide) {
1072                         BM_elem_hide_set(bm, *data, FALSE);
1073                 }
1074
1075                 BM_elem_flag_disable(*data, hflag);
1076         }
1077 }
1078
1079 int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
1080 {
1081         int count = 0;
1082
1083         if (v->e) {
1084                 BMEdge *curedge;
1085                 const int len = bmesh_disk_count(v);
1086                 int i;
1087                 
1088                 for (i = 0, curedge = v->e; i < len; i++) {
1089                         if (BMO_elem_flag_test(bm, curedge, oflag))
1090                                 count++;
1091                         curedge = bmesh_disk_edge_next(curedge, v);
1092                 }
1093         }
1094
1095         return count;
1096 }
1097
1098 /**
1099  * \brief BMO_FLAG_BUFFER
1100  *
1101  * Flags elements in a slots buffer
1102  */
1103 void BMO_slot_buffer_flag_enable(BMesh *bm,
1104                                  BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1105                                  const char htype, const short oflag)
1106 {
1107         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1108         BMHeader **data =  slot->data.p;
1109         int i;
1110
1111         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1112         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1113
1114         for (i = 0; i < slot->len; i++) {
1115                 if (!(htype & data[i]->htype))
1116                         continue;
1117
1118                 BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
1119         }
1120 }
1121
1122 /**
1123  * \brief BMO_FLAG_BUFFER
1124  *
1125  * Removes flags from elements in a slots buffer
1126  */
1127 void BMO_slot_buffer_flag_disable(BMesh *bm,
1128                                   BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1129                                   const char htype, const short oflag)
1130 {
1131         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1132         BMHeader **data = (BMHeader **)slot->data.buf;
1133         int i;
1134
1135         BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1136         BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1137
1138         for (i = 0; i < slot->len; i++) {
1139                 if (!(htype & data[i]->htype))
1140                         continue;
1141
1142                 BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
1143         }
1144 }
1145
1146
1147 /**
1148  * \brief ALLOC/FREE FLAG LAYER
1149  *
1150  * Used by operator stack to free/allocate
1151  * private flag data. This is allocated
1152  * using a mempool so the allocation/frees
1153  * should be quite fast.
1154  *
1155  * BMESH_TODO:
1156  * Investigate not freeing flag layers until
1157  * all operators have been executed. This would
1158  * save a lot of realloc potentially.
1159  */
1160 static void bmo_flag_layer_alloc(BMesh *bm)
1161 {
1162         BMElemF *ele;
1163         /* set the index values since we are looping over all data anyway,
1164          * may save time later on */
1165         int i;
1166
1167         BMIter iter;
1168         BLI_mempool *oldpool = bm->toolflagpool;  /* old flag pool */
1169         BLI_mempool *newpool;
1170         void *oldflags;
1171
1172         /* store memcpy size for reuse */
1173         const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
1174
1175         BLI_assert(oldpool != NULL);
1176
1177         bm->totflags++;
1178
1179         /* allocate new flag poo */
1180         bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, 512, 512, 0);
1181         
1182         /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
1183         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1184                 oldflags = ele->oflags;
1185                 ele->oflags = BLI_mempool_calloc(newpool);
1186                 memcpy(ele->oflags, oldflags, old_totflags_size);
1187                 BM_elem_index_set(ele, i); /* set_inline */
1188                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1189         }
1190         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1191                 oldflags = ele->oflags;
1192                 ele->oflags = BLI_mempool_calloc(newpool);
1193                 memcpy(ele->oflags, oldflags, old_totflags_size);
1194                 BM_elem_index_set(ele, i); /* set_inline */
1195                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1196         }
1197         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1198                 oldflags = ele->oflags;
1199                 ele->oflags = BLI_mempool_calloc(newpool);
1200                 memcpy(ele->oflags, oldflags, old_totflags_size);
1201                 BM_elem_index_set(ele, i); /* set_inline */
1202                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1203         }
1204
1205         bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1206
1207         BLI_mempool_destroy(oldpool);
1208 }
1209
1210 static void bmo_flag_layer_free(BMesh *bm)
1211 {
1212         BMElemF *ele;
1213         /* set the index values since we are looping over all data anyway,
1214          * may save time later on */
1215         int i;
1216
1217         BMIter iter;
1218         BLI_mempool *oldpool = bm->toolflagpool;
1219         BLI_mempool *newpool;
1220         void *oldflags;
1221         
1222         /* store memcpy size for reuse */
1223         const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
1224
1225         /* de-increment the totflags first.. */
1226         bm->totflags--;
1227         /* allocate new flag poo */
1228         bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, 0);
1229         
1230         /* now go through and memcpy all the flag */
1231         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1232                 oldflags = ele->oflags;
1233                 ele->oflags = BLI_mempool_calloc(newpool);
1234                 memcpy(ele->oflags, oldflags, new_totflags_size);
1235                 BM_elem_index_set(ele, i); /* set_inline */
1236                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1237         }
1238         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1239                 oldflags = ele->oflags;
1240                 ele->oflags = BLI_mempool_calloc(newpool);
1241                 memcpy(ele->oflags, oldflags, new_totflags_size);
1242                 BM_elem_index_set(ele, i); /* set_inline */
1243                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1244         }
1245         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1246                 oldflags = ele->oflags;
1247                 ele->oflags = BLI_mempool_calloc(newpool);
1248                 memcpy(ele->oflags, oldflags, new_totflags_size);
1249                 BM_elem_index_set(ele, i); /* set_inline */
1250                 BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele);
1251         }
1252
1253         bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1254
1255         BLI_mempool_destroy(oldpool);
1256 }
1257
1258 static void bmo_flag_layer_clear(BMesh *bm)
1259 {
1260         BMElemF *ele;
1261         /* set the index values since we are looping over all data anyway,
1262          * may save time later on */
1263         int i;
1264
1265         BMIter iter;
1266         const int totflags_offset = bm->totflags - 1;
1267
1268         /* now go through and memcpy all the flag */
1269         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1270                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1271                 BM_elem_index_set(ele, i); /* set_inline */
1272         }
1273         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1274                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1275                 BM_elem_index_set(ele, i); /* set_inline */
1276         }
1277         BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1278                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1279                 BM_elem_index_set(ele, i); /* set_inline */
1280         }
1281
1282         bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1283 }
1284
1285 void *BMO_slot_buffer_elem_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
1286 {
1287         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1288         
1289         if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
1290                 return NULL;
1291
1292         return slot->data.buf ? *slot->data.buf : NULL;
1293 }
1294
1295 /**
1296  * \brief New Iterator
1297  *
1298  * \param restrictmask restricts the iteration to certain element types
1299  * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
1300  * over an element buffer (not a mapping). */
1301 void *BMO_iter_new(BMOIter *iter,
1302                    BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1303                    const char restrictmask)
1304 {
1305         BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1306
1307         memset(iter, 0, sizeof(BMOIter));
1308
1309         iter->slot = slot;
1310         iter->cur = 0;
1311         iter->restrictmask = restrictmask;
1312
1313         if (iter->slot->slot_type == BMO_OP_SLOT_MAPPING) {
1314                 if (iter->slot->data.ghash) {
1315                         BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1316                 }
1317                 else {
1318                         return NULL;
1319                 }
1320         }
1321
1322         return BMO_iter_step(iter);
1323 }
1324
1325 void *BMO_iter_step(BMOIter *iter)
1326 {
1327         BMOpSlot *slot = iter->slot;
1328         if (slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
1329                 BMHeader *ele;
1330
1331                 if (iter->cur >= slot->len) {
1332                         return NULL;
1333                 }
1334
1335                 ele = slot->data.buf[iter->cur++];
1336                 while (!(iter->restrictmask & ele->htype)) {
1337                         if (iter->cur >= slot->len) {
1338                                 return NULL;
1339                         }
1340
1341                         ele = slot->data.buf[iter->cur++];
1342                         BLI_assert((ele == NULL) || (slot->slot_subtype.elem & ele->htype));
1343                 }
1344
1345                 BLI_assert((ele == NULL) || (slot->slot_subtype.elem & ele->htype));
1346
1347                 return ele;
1348         }
1349         else if (slot->slot_type == BMO_OP_SLOT_MAPPING) {
1350                 BMOElemMapping *map;
1351                 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1352                 map = BLI_ghashIterator_getValue(&iter->giter);
1353                 
1354                 iter->val = BMO_OP_SLOT_MAPPING_DATA(map);
1355
1356                 BLI_ghashIterator_step(&iter->giter);
1357
1358                 return ret;
1359         }
1360         else {
1361                 BLI_assert(0);
1362         }
1363
1364         return NULL;
1365 }
1366
1367 /* used for iterating over mapping */
1368 void *BMO_iter_map_value(BMOIter *iter)
1369 {
1370         return iter->val;
1371 }
1372
1373 void *BMO_iter_map_value_p(BMOIter *iter)
1374 {
1375         return *((void **)iter->val);
1376 }
1377
1378 float BMO_iter_map_value_f(BMOIter *iter)
1379 {
1380         return *((float *)iter->val);
1381 }
1382
1383 /* error syste */
1384 typedef struct BMOpError {
1385         struct BMOpError *next, *prev;
1386         int errorcode;
1387         BMOperator *op;
1388         const char *msg;
1389 } BMOpError;
1390
1391 void BMO_error_clear(BMesh *bm)
1392 {
1393         while (BMO_error_pop(bm, NULL, NULL));
1394 }
1395
1396 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1397 {
1398         BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1399         
1400         err->errorcode = errcode;
1401         if (!msg) {
1402                 msg = bmo_error_messages[errcode];
1403         }
1404         err->msg = msg;
1405         err->op = owner;
1406         
1407         BLI_addhead(&bm->errorstack, err);
1408 }
1409
1410 int BMO_error_occurred(BMesh *bm)
1411 {
1412         return bm->errorstack.first != NULL;
1413 }
1414
1415 /* returns error code or 0 if no error */
1416 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1417 {
1418         BMOpError *err = bm->errorstack.first;
1419         if (!err) {
1420                 return 0;
1421         }
1422
1423         if (msg) *msg = err->msg;
1424         if (op) *op = err->op;
1425         
1426         return err->errorcode;
1427 }
1428
1429 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1430 {
1431         int errorcode = BMO_error_get(bm, msg, op);
1432         
1433         if (errorcode) {
1434                 BMOpError *err = bm->errorstack.first;
1435                 
1436                 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1437                 MEM_freeN(err);
1438         }
1439
1440         return errorcode;
1441 }
1442
1443
1444 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1445
1446 static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
1447 {
1448         int i = 0;
1449
1450         while (slot_args->slot_name) {
1451                 if (strncmp(identifier, slot_args->slot_name, MAX_SLOTNAME) == 0) {
1452                         return i;
1453                 }
1454                 slot_args++;
1455                 i++;
1456         }
1457
1458         return -1;
1459 }
1460
1461 static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
1462 {
1463         int i = bmo_name_to_slotcode(slot_args, identifier);
1464         if (i < 0) {
1465                 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, identifier);
1466         }
1467
1468         return i;
1469 }
1470
1471 static int bmo_opname_to_opcode(const char *opname)
1472 {
1473         int i;
1474
1475         for (i = 0; i < bmo_opdefines_total; i++) {
1476                 if (!strcmp(opname, bmo_opdefines[i]->opname)) {
1477                         return i;
1478                 }
1479         }
1480
1481         fprintf(stderr, "%s: could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1482         return -1;
1483 }
1484
1485 /**
1486  * \brief Format Strings for #BMOperator Initialization.
1487  *
1488  * This system is used to execute or initialize an operator,
1489  * using a formatted-string system.
1490  *
1491  * The basic format for the format string is:
1492  * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
1493  *
1494  * Example:
1495  *
1496  * \code{.c}
1497  *     BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
1498  *                  "delete context=%i geom=%hv",
1499  *                  DEL_ONLYFACES, BM_ELEM_SELECT);
1500  * \endcode
1501  *
1502  *
1503  * **Primitive Types**
1504  * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
1505  * - `i` - int. #BMO_OP_SLOT_INT
1506  * - `f` - float. #BMO_OP_SLOT_FLT
1507  * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
1508  * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
1509  * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
1510  * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
1511  *
1512  *
1513  * **Utility**
1514  *
1515  * Pass an existing slot which is copied to either an input or output slot.
1516  * Taking the operator and slot-name pair of args.
1517  * - `s` - slot_in (lower case)
1518  * - `S` - slot_out (upper case)
1519  *
1520  *
1521  * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
1522  * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
1523  * - `av` - all verts
1524  * - `ae` - all edges
1525  * - `af` - all faces
1526  * - `hv` - header flagged verts (hflag)
1527  * - `he` - header flagged edges (hflag)
1528  * - `hf` - header flagged faces (hflag)
1529  * - `Hv` - header flagged verts (hflag off)
1530  * - `He` - header flagged edges (hflag off)
1531  * - `Hf` - header flagged faces (hflag off)
1532  * - `fv` - flagged verts (oflag)
1533  * - `fe` - flagged edges (oflag)
1534  * - `ff` - flagged faces (oflag)
1535  * - `Fv` - flagged verts (oflag off)
1536  * - `Fe` - flagged edges (oflag off)
1537  * - `Ff` - flagged faces (oflag off)
1538  *
1539  * \note The common v/e/f suffix can be mixed,
1540  * so `avef` is can be used for all verts, edges and faces.
1541  * Order is not important so `Hfev` is also valid (all unflagged verts, edges and faces).
1542  */
1543
1544 int BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, va_list vlist)
1545 {
1546 //      BMOpDefine *def;
1547         char *opname, *ofmt, *fmt;
1548         char slot_name[64] = {0};
1549         int i /*, n = strlen(fmt) */, stop /*, slot_code = -1 */, type, state;
1550         char htype;
1551         int noslot = 0;
1552
1553
1554         /* basic useful info to help find where bmop formatting strings fail */
1555         const char *err_reason = "Unknown";
1556         int lineno = -1;
1557
1558 #define GOTO_ERROR(reason)   \
1559         {                        \
1560                 err_reason = reason; \
1561                 lineno = __LINE__;   \
1562                 goto error;          \
1563         } (void)0
1564
1565         /* we muck around in here, so dup i */
1566         fmt = ofmt = BLI_strdup(_fmt);
1567         
1568         /* find operator name */
1569         i = strcspn(fmt, " ");
1570
1571         opname = fmt;
1572         if (!opname[i]) noslot = 1;
1573         opname[i] = '\0';
1574
1575         fmt += i + (noslot ? 0 : 1);
1576         
1577         i = bmo_opname_to_opcode(opname);
1578
1579         if (i == -1) {
1580                 MEM_freeN(ofmt);
1581                 return FALSE;
1582         }
1583
1584         BMO_op_init(bm, op, flag, opname);
1585 //      def = bmo_opdefines[i];
1586         
1587         i = 0;
1588         state = 1; /* 0: not inside slot_code name, 1: inside slot_code name */
1589
1590         while (*fmt) {
1591                 if (state) {
1592                         /* jump past leading whitespac */
1593                         i = strspn(fmt, " ");
1594                         fmt += i;
1595                         
1596                         /* ignore trailing whitespac */
1597                         if (!fmt[i])
1598                                 break;
1599
1600                         /* find end of slot name, only "slot=%f", can be used */
1601                         i = strcspn(fmt, "=");
1602                         if (!fmt[i]) {
1603                                 GOTO_ERROR("could not match end of slot name");
1604                         }
1605
1606                         fmt[i] = 0;
1607
1608                         if (bmo_name_to_slotcode_check(op->slots_in, fmt) < 0) {
1609                                 GOTO_ERROR("name to slot code check failed");
1610                         }
1611                         
1612                         BLI_strncpy(slot_name, fmt, sizeof(slot_name));
1613                         
1614                         state = 0;
1615                         fmt += i;
1616                 }
1617                 else {
1618                         switch (*fmt) {
1619                                 case ' ':
1620                                 case '=':
1621                                 case '%':
1622                                         break;
1623                                 case 'm':
1624                                 {
1625                                         int size, c;
1626
1627                                         c = NEXT_CHAR(fmt);
1628                                         fmt++;
1629
1630                                         if      (c == '3') size = 3;
1631                                         else if (c == '4') size = 4;
1632                                         else GOTO_ERROR("matrix size was not 3 or 4");
1633
1634                                         BMO_slot_mat_set(op, op->slots_in, slot_name, va_arg(vlist, void *), size);
1635                                         state = 1;
1636                                         break;
1637                                 }
1638                                 case 'v':
1639                                 {
1640                                         BMO_slot_vec_set(op->slots_in, slot_name, va_arg(vlist, float *));
1641                                         state = 1;
1642                                         break;
1643                                 }
1644                                 case 'e':  /* single vert/edge/face */
1645                                 {
1646                                         BMHeader *ele = va_arg(vlist, void *);
1647                                         BMOpSlot *slot = BMO_slot_get(op->slots_in, slot_name);
1648
1649                                         BMO_slot_buffer_from_single(op, slot, ele);
1650
1651                                         state = 1;
1652                                         break;
1653                                 }
1654                                 case 's':
1655                                 case 'S':
1656                                 {
1657                                         BMOperator *op_other        = va_arg(vlist, void *);
1658                                         const char *slot_name_other = va_arg(vlist, char *);
1659
1660                                         if (*fmt == 's') {
1661                                                 BLI_assert(bmo_name_to_slotcode_check(op_other->slots_in, slot_name_other) != -1);
1662                                                 BMO_slot_copy(op_other, slots_in, slot_name_other,
1663                                                               op,       slots_in, slot_name);
1664                                         }
1665                                         else {
1666                                                 BLI_assert(bmo_name_to_slotcode_check(op_other->slots_out, slot_name_other) != -1);
1667                                                 BMO_slot_copy(op_other, slots_out, slot_name_other,
1668                                                               op,       slots_in, slot_name);
1669                                         }
1670                                         state = 1;
1671                                         break;
1672                                 }
1673                                 case 'i':
1674                                         BMO_slot_int_set(op->slots_in, slot_name, va_arg(vlist, int));
1675                                         state = 1;
1676                                         break;
1677                                 case 'b':
1678                                         BMO_slot_bool_set(op->slots_in, slot_name, va_arg(vlist, int));
1679                                         state = 1;
1680                                         break;
1681                                 case 'p':
1682                                         BMO_slot_ptr_set(op->slots_in, slot_name, va_arg(vlist, void *));
1683                                         state = 1;
1684                                         break;
1685                                 case 'f':
1686                                 case 'F':
1687                                 case 'h':
1688                                 case 'H':
1689                                 case 'a':
1690                                         type = *fmt;
1691
1692                                         if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\0') {
1693                                                 BMO_slot_float_set(op->slots_in, slot_name, va_arg(vlist, double));
1694                                         }
1695                                         else {
1696                                                 htype = 0;
1697                                                 stop = 0;
1698                                                 while (1) {
1699                                                         switch (NEXT_CHAR(fmt)) {
1700                                                                 case 'f': htype |= BM_FACE; break;
1701                                                                 case 'e': htype |= BM_EDGE; break;
1702                                                                 case 'v': htype |= BM_VERT; break;
1703                                                                 default:
1704                                                                         stop = 1;
1705                                                                         break;
1706                                                         }
1707                                                         if (stop) {
1708                                                                 break;
1709                                                         }
1710
1711                                                         fmt++;
1712                                                 }
1713
1714                                                 if (type == 'h') {
1715                                                         BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1716                                                 }
1717                                                 else if (type == 'H') {
1718                                                         BMO_slot_buffer_from_disabled_hflag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1719                                                 }
1720                                                 else if (type == 'a') {
1721                                                         BMO_slot_buffer_from_all(bm, op, op->slots_in, slot_name, htype);
1722                                                 }
1723                                                 else if (type == 'f') {
1724                                                         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1725                                                 }
1726                                                 else if (type == 'F') {
1727                                                         BMO_slot_buffer_from_disabled_flag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1728                                                 }
1729                                         }
1730
1731                                         state = 1;
1732                                         break;
1733                                 default:
1734                                         fprintf(stderr,
1735                                                 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1736                                                 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1737                                         break;
1738                         }
1739                 }
1740                 fmt++;
1741         }
1742
1743         MEM_freeN(ofmt);
1744         return TRUE;
1745 error:
1746
1747         /* non urgent todo - explain exactly what is failing */
1748         fprintf(stderr, "%s: error parsing formatting string\n", __func__);
1749
1750         fprintf(stderr, "string: '%s', position %d\n", _fmt, (int)(fmt - ofmt));
1751         fprintf(stderr, "         ");
1752         {
1753                 int pos = (int)(fmt - ofmt);
1754                 int i;
1755                 for (i = 0; i < pos; i++) {
1756                         fprintf(stderr, " ");
1757                 }
1758                 fprintf(stderr, "^\n");
1759         }
1760
1761         fprintf(stderr, "source code:  %s:%d\n", __FILE__, lineno);
1762
1763         fprintf(stderr, "reason: %s\n", err_reason);
1764
1765
1766         MEM_freeN(ofmt);
1767
1768         BMO_op_finish(bm, op);
1769         return FALSE;
1770
1771 #undef GOTO_ERROR
1772
1773 }
1774
1775
1776 int BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, ...)
1777 {
1778         va_list list;
1779
1780         va_start(list, fmt);
1781         if (!BMO_op_vinitf(bm, op, flag, fmt, list)) {
1782                 printf("%s: failed\n", __func__);
1783                 va_end(list);
1784                 return FALSE;
1785         }
1786         va_end(list);
1787
1788         return TRUE;
1789 }
1790
1791 int BMO_op_callf(BMesh *bm, const int flag, const char *fmt, ...)
1792 {
1793         va_list list;
1794         BMOperator op;
1795
1796         va_start(list, fmt);
1797         if (!BMO_op_vinitf(bm, &op, flag, fmt, list)) {
1798                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1799                 va_end(list);
1800                 return FALSE;
1801         }
1802
1803         BMO_op_exec(bm, &op);
1804         BMO_op_finish(bm, &op);
1805
1806         va_end(list);
1807         return TRUE;
1808 }