api name conventions, more minor changes: flag set/clear --> enable/disable
[blender-staging.git] / source / blender / bmesh / intern / bmesh_operators.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/intern/bmesh_operators.c
24  *  \ingroup bmesh
25  *
26  * BMesh operator access.
27  */
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_utildefines.h"
32 #include "BLI_string.h"
33 #include "BLI_math.h"
34 #include "BLI_memarena.h"
35 #include "BLI_mempool.h"
36 #include "BLI_listbase.h"
37 #include "BLI_array.h"
38
39 #include "bmesh.h"
40 #include "bmesh_private.h"
41
42 /* forward declarations */
43 static void bmo_flag_layer_alloc(BMesh *bm);
44 static void bmo_flag_layer_free(BMesh *bm);
45 static void bmo_flag_layer_clear(BMesh *bm);
46 static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name);
47 static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name);
48 static int bmesh_opname_to_opcode(const char *opname);
49
50 static const char *bmo_error_messages[] = {
51         NULL,
52         "Self intersection error",
53         "Could not dissolve vert",
54         "Could not connect vertices",
55         "Could not traverse mesh",
56         "Could not dissolve faces",
57         "Could not dissolve vertices",
58         "Tesselation error",
59         "Can not deal with non-manifold geometry",
60         "Invalid selection",
61         "Internal mesh error",
62 };
63
64
65 /* operator slot type information - size of one element of the type given. */
66 const int BMO_OPSLOT_TYPEINFO[] = {
67         0,
68         sizeof(int),
69         sizeof(float),
70         sizeof(void *),
71         0, /* unused */
72         0, /* unused */
73         0, /* unused */
74         sizeof(void *), /* pointer buffer */
75         sizeof(BMOElemMapping)
76 };
77
78 /* Dummy slot so there is something to return when slot name lookup fails */
79 static BMOpSlot BMOpEmptySlot = {0};
80
81 void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
82 {
83         op->flag |= op_flag;
84 }
85
86 void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
87 {
88         op->flag &= ~op_flag;
89 }
90
91 /*
92  * BMESH OPSTACK PUSH
93  *
94  * Pushes the opstack down one level
95  * and allocates a new flag layer if
96  * appropriate.
97  */
98 void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
99 {
100         bm->stackdepth++;
101
102         /* add flag layer, if appropriate */
103         if (bm->stackdepth > 1)
104                 bmo_flag_layer_alloc(bm);
105         else
106                 bmo_flag_layer_clear(bm);
107 }
108
109 /*
110  * BMESH OPSTACK POP
111  *
112  * Pops the opstack one level
113  * and frees a flag layer if appropriate
114  * BMESH_TODO: investigate NOT freeing flag
115  * layers.
116  */
117 void BMO_pop(BMesh *bm)
118 {
119         if (bm->stackdepth > 1)
120                 bmo_flag_layer_free(bm);
121
122         bm->stackdepth--;
123 }
124
125 /*
126  * BMESH OPSTACK INIT OP
127  *
128  * Initializes an operator structure
129  * to a certain type
130  */
131 void BMO_op_init(BMesh *bm, BMOperator *op, const char *opname)
132 {
133         int i, opcode = bmesh_opname_to_opcode(opname);
134
135 #ifdef DEBUG
136         BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
137 #else
138         (void)bm;
139 #endif
140
141         if (opcode == -1) {
142                 opcode = 0; /* error!, already printed, have a better way to handle this? */
143         }
144
145         memset(op, 0, sizeof(BMOperator));
146         op->type = opcode;
147         op->flag = opdefines[opcode]->flag;
148         
149         /* initialize the operator slot types */
150         for (i = 0; opdefines[opcode]->slottypes[i].type; i++) {
151                 op->slots[i].slottype = opdefines[opcode]->slottypes[i].type;
152                 op->slots[i].index = i;
153         }
154
155         /* callback */
156         op->exec = opdefines[opcode]->exec;
157
158         /* memarena, used for operator's slot buffers */
159         op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bmesh operator");
160         BLI_memarena_use_calloc (op->arena);
161 }
162
163 /*
164  * BMESH OPSTACK EXEC OP
165  *
166  * Executes a passed in operator. This handles
167  * the allocation and freeing of temporary flag
168  * layers and starting/stopping the modelling
169  * loop. Can be called from other operators
170  * exec callbacks as well.
171  */
172 void BMO_op_exec(BMesh *bm, BMOperator *op)
173 {
174         
175         BMO_push(bm, op);
176
177         if (bm->stackdepth == 2)
178                 bmesh_begin_edit(bm, op->flag);
179         op->exec(bm, op);
180         
181         if (bm->stackdepth == 2)
182                 bmesh_end_edit(bm, op->flag);
183         
184         BMO_pop(bm);
185 }
186
187 /*
188  * BMESH OPSTACK FINISH OP
189  *
190  * Does housekeeping chores related to finishing
191  * up an operator.
192  */
193 void BMO_op_finish(BMesh *bm, BMOperator *op)
194 {
195         BMOpSlot *slot;
196         int i;
197
198         for (i = 0; opdefines[op->type]->slottypes[i].type; i++) {
199                 slot = &op->slots[i];
200                 if (slot->slottype == BMOP_OPSLOT_MAPPING) {
201                         if (slot->data.ghash)
202                                 BLI_ghash_free(slot->data.ghash, NULL, NULL);
203                 }
204         }
205
206         BLI_memarena_free(op->arena);
207
208 #ifdef DEBUG
209         BM_ELEM_INDEX_VALIDATE(bm, "post bmo", opdefines[op->type]->name);
210 #else
211         (void)bm;
212 #endif
213 }
214
215 /*
216  * BMESH OPSTACK HAS SLOT
217  *
218  * Returns 1 if the named slot exists on the given operator,
219  * otherwise returns 0.
220  */
221 int BMO_slot_exists(BMOperator *op, const char *slotname)
222 {
223         int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname);
224         return (slotcode >= 0);
225 }
226
227 /*
228  * BMESH OPSTACK GET SLOT
229  *
230  * Returns a pointer to the slot of
231  * type 'slotcode'
232  */
233 BMOpSlot *BMO_slot_get(BMOperator *op, const char *slotname)
234 {
235         int slotcode = bmesh_name_to_slotcode_check(opdefines[op->type], slotname);
236
237         if (slotcode < 0) {
238                 return &BMOpEmptySlot;
239         }
240
241         return &(op->slots[slotcode]);
242 }
243
244 /*
245  * BMESH OPSTACK COPY SLOT
246  *
247  * Copies data from one slot to another
248  */
249 void BMO_slot_copy(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
250 {
251         BMOpSlot *source_slot = BMO_slot_get(source_op, src);
252         BMOpSlot *dest_slot = BMO_slot_get(dest_op, dst);
253
254         if (source_slot == dest_slot)
255                 return;
256
257         if (source_slot->slottype != dest_slot->slottype)
258                 return;
259         
260         if (dest_slot->slottype > BMOP_OPSLOT_VEC) {
261                 if (dest_slot->slottype != BMOP_OPSLOT_MAPPING) {
262                         /* do buffer copy */
263                         dest_slot->data.buf = NULL;
264                         dest_slot->len = source_slot->len;
265                         if (dest_slot->len) {
266                                 const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
267                                 dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
268                                 memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
269                         }
270                 }
271                 else {
272                         GHashIterator it;
273                         BMOElemMapping *srcmap, *dstmap;
274
275                         /* sanity check */
276                         if (!source_slot->data.ghash) return;
277                         
278                         if (!dest_slot->data.ghash) {
279                                 dest_slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
280                                                                       BLI_ghashutil_ptrcmp, "bmesh operator 2");
281                         }
282
283                         BLI_ghashIterator_init(&it, source_slot->data.ghash);
284                         for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
285                               BLI_ghashIterator_step(&it))
286                         {
287                                 dstmap = BLI_memarena_alloc(dest_op->arena, sizeof(*dstmap) + srcmap->len);
288
289                                 dstmap->element = srcmap->element;
290                                 dstmap->len = srcmap->len;
291                                 memcpy(dstmap + 1, srcmap + 1, srcmap->len);
292
293                                 BLI_ghash_insert(dest_slot->data.ghash, dstmap->element, dstmap);
294                         }
295                 }
296         }
297         else {
298                 dest_slot->data = source_slot->data;
299         }
300 }
301
302 /*
303  * BMESH OPSTACK SET XXX
304  *
305  * Sets the value of a slot depending on it's type
306  *
307  */
308
309 void BMO_slot_float_set(BMOperator *op, const char *slotname, float f)
310 {
311         BMOpSlot *slot = BMO_slot_get(op, slotname);
312         if (!(slot->slottype == BMOP_OPSLOT_FLT))
313                 return;
314
315         slot->data.f = f;
316 }
317
318 void BMO_slot_int_set(BMOperator *op, const char *slotname, int i)
319 {
320         BMOpSlot *slot = BMO_slot_get(op, slotname);
321         if (!(slot->slottype == BMOP_OPSLOT_INT))
322                 return;
323
324         slot->data.i = i;
325 }
326
327 /* only supports square mats */
328 void BMO_slot_mat_set(struct BMOperator *op, const char *slotname, float *mat, int size)
329 {
330         BMOpSlot *slot = BMO_slot_get(op, slotname);
331         if (!(slot->slottype == BMOP_OPSLOT_MAT))
332                 return;
333
334         slot->len = 4;
335         slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
336         
337         if (size == 4) {
338                 memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
339         }
340         else if (size == 3) {
341                 copy_m4_m3(slot->data.p, (float (*)[3])mat);
342         }
343         else {
344                 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
345
346                 memset(slot->data.p, 0, sizeof(float) * 4 * 4);
347                 return;
348         }
349 }
350
351 void BMO_slot_mat4_set(struct BMOperator *op, const char *slotname, float mat[4][4])
352 {
353         BMOpSlot *slot = BMO_slot_get(op, slotname);
354         if (!(slot->slottype == BMOP_OPSLOT_MAT))
355                 return;
356
357         memcpy(mat, slot->data.p, sizeof(float) * 4 * 4);
358 }
359
360 void BMO_slot_mat3_set(struct BMOperator *op, const char *slotname, float mat[3][3])
361 {
362         BMOpSlot *slot = BMO_slot_get(op, slotname);
363         if (!(slot->slottype == BMOP_OPSLOT_MAT))
364                 return;
365
366         copy_m3_m4(mat, slot->data.p);
367 }
368
369 void BMO_slot_ptr_set(BMOperator *op, const char *slotname, void *p)
370 {
371         BMOpSlot *slot = BMO_slot_get(op, slotname);
372         if (!(slot->slottype == BMOP_OPSLOT_PNT))
373                 return;
374
375         slot->data.p = p;
376 }
377
378 void BMO_slot_vec_set(BMOperator *op, const char *slotname, const float vec[3])
379 {
380         BMOpSlot *slot = BMO_slot_get(op, slotname);
381         if (!(slot->slottype == BMOP_OPSLOT_VEC))
382                 return;
383
384         copy_v3_v3(slot->data.vec, vec);
385 }
386
387
388 float BMO_slot_float_get(BMOperator *op, const char *slotname)
389 {
390         BMOpSlot *slot = BMO_slot_get(op, slotname);
391         if (!(slot->slottype == BMOP_OPSLOT_FLT))
392                 return 0.0f;
393
394         return slot->data.f;
395 }
396
397 int BMO_slot_int_get(BMOperator *op, const char *slotname)
398 {
399         BMOpSlot *slot = BMO_slot_get(op, slotname);
400         if (!(slot->slottype == BMOP_OPSLOT_INT))
401                 return 0;
402
403         return slot->data.i;
404 }
405
406
407 void *BMO_slot_ptr_get(BMOperator *op, const char *slotname)
408 {
409         BMOpSlot *slot = BMO_slot_get(op, slotname);
410         if (!(slot->slottype == BMOP_OPSLOT_PNT))
411                 return NULL;
412
413         return slot->data.p;
414 }
415
416 void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3])
417 {
418         BMOpSlot *slot = BMO_slot_get(op, slotname);
419         if (!(slot->slottype == BMOP_OPSLOT_VEC))
420                 return;
421
422         copy_v3_v3(r_vec, slot->data.vec);
423 }
424
425 /*
426  * BMO_COUNTFLAG
427  *
428  * Counts the number of elements of a certain type that
429  * have a specific flag set.
430  *
431  */
432
433 int BMO_mesh_flag_count(BMesh *bm, const short oflag, const char htype)
434 {
435         BMIter elements;
436         BMHeader *e;
437         int count = 0;
438
439         if (htype & BM_VERT) {
440                 for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
441                         if (BMO_elem_flag_test(bm, e, oflag))
442                                 count++;
443                 }
444         }
445         if (htype & BM_EDGE) {
446                 for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
447                         if (BMO_elem_flag_test(bm, e, oflag))
448                                 count++;
449                 }
450         }
451         if (htype & BM_FACE) {
452                 for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
453                         if (BMO_elem_flag_test(bm, e, oflag))
454                                 count++;
455                 }
456         }
457
458         return count;
459 }
460
461 void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
462 {
463         const char iter_types[3] = {BM_VERTS_OF_MESH,
464                                     BM_EDGES_OF_MESH,
465                                     BM_FACES_OF_MESH};
466
467         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
468
469         BMIter iter;
470         BMHeader *ele;
471         int i;
472
473         for (i = 0; i < 3; i++) {
474                 if (htype & flag_types[i]) {
475                         BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
476                                 BMO_elem_flag_disable(bm, ele, oflag);
477                         }
478                 }
479         }
480 }
481
482 int BMO_slot_buf_count(struct BMesh *UNUSED(bm), struct BMOperator *op, const char *slotname)
483 {
484         BMOpSlot *slot = BMO_slot_get(op, slotname);
485         
486         /* check if its actually a buffer */
487         if (!(slot->slottype > BMOP_OPSLOT_VEC))
488                 return 0;
489
490         return slot->len;
491 }
492
493 int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
494 {
495         BMOpSlot *slot = BMO_slot_get(op, slotname);
496         
497         /* check if its actually a buffer */
498         if (!(slot->slottype == BMOP_OPSLOT_MAPPING))
499                 return 0;
500
501         return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
502 }
503
504 #if 0
505 void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd)
506 {
507         BMOpSlot *slot = &op->slots[slotcode];
508         void *tmp;
509         
510         /* check if its actually a buffer */
511         if (!(slot->slottype > BMOP_OPSLOT_VEC))
512                 return NULL;
513
514         if (slot->flag & BMOS_DYNAMIC_ARRAY) {
515                 if (slot->len >= slot->size) {
516                         slot->size = (slot->size + 1 + totadd) * 2;
517
518                         tmp = slot->data.buf;
519                         slot->data.buf = MEM_callocN(BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size, "opslot dynamic array");
520                         memcpy(slot->data.buf, tmp, BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size);
521                         MEM_freeN(tmp);
522                 }
523
524                 slot->len += totadd;
525         }
526         else {
527                 slot->flag |= BMOS_DYNAMIC_ARRAY;
528                 slot->len += totadd;
529                 slot->size = slot->len + 2;
530                 tmp = slot->data.buf;
531                 slot->data.buf = MEM_callocN(BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len, "opslot dynamic array");
532                 memcpy(slot->data.buf, tmp, BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len);
533         }
534
535         return slot->data.buf;
536 }
537 #endif
538
539 void BMO_slot_map_to_flag(struct BMesh *bm, struct BMOperator *op,
540                           const char *slotname, const short oflag)
541 {
542         GHashIterator it;
543         BMOpSlot *slot = BMO_slot_get(op, slotname);
544         BMHeader *ele;
545
546         /* sanity check */
547         if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
548         if (!slot->data.ghash) return;
549
550         BLI_ghashIterator_init(&it, slot->data.ghash);
551         for ( ; (ele = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
552                 BMO_elem_flag_enable(bm, ele, oflag);
553         }
554 }
555
556 static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slotname, int len)
557 {
558         BMOpSlot *slot = BMO_slot_get(op, slotname);
559
560         /* check if its actually a buffer */
561         if (!(slot->slottype > BMOP_OPSLOT_VEC))
562                 return NULL;
563         
564         slot->len = len;
565         if (len)
566                 slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slottype] * len);
567         return slot->data.buf;
568 }
569
570 /*
571  * BMO_ALL_TO_SLOT
572  *
573  * Copies all elements of a certain type into an operator slot.
574  *
575  */
576
577 static void BMO_slot_from_all(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
578 {
579         BMIter elements;
580         BMHeader *e;
581         BMOpSlot *output = BMO_slot_get(op, slotname);
582         int totelement = 0, i = 0;
583         
584         if (htype & BM_VERT) totelement += bm->totvert;
585         if (htype & BM_EDGE) totelement += bm->totedge;
586         if (htype & BM_FACE) totelement += bm->totface;
587
588         if (totelement) {
589                 bmo_slot_buffer_alloc(op, slotname, totelement);
590
591                 if (htype & BM_VERT) {
592                         for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
593                                 ((BMHeader **)output->data.p)[i] = e;
594                                 i++;
595                         }
596                 }
597
598                 if (htype & BM_EDGE) {
599                         for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
600                                 ((BMHeader **)output->data.p)[i] = e;
601                                 i++;
602                         }
603                 }
604
605                 if (htype & BM_FACE) {
606                         for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
607                                 ((BMHeader **)output->data.p)[i] = e;
608                                 i++;
609                         }
610                 }
611         }
612 }
613
614 /*
615  * BMO_HEADERFLAG_TO_SLOT
616  *
617  * Copies elements of a certain type, which have a certain header flag set
618  * into a slot for an operator.
619  */
620
621 void BMO_slot_from_hflag(BMesh *bm, BMOperator *op, const char *slotname,
622                          const char hflag, const char htype)
623 {
624         BMIter elements;
625         BMHeader *e;
626         BMOpSlot *output = BMO_slot_get(op, slotname);
627         int totelement = 0, i = 0;
628         
629         totelement = BM_mesh_count_flag(bm, htype, hflag, 1);
630
631         if (totelement) {
632                 bmo_slot_buffer_alloc(op, slotname, totelement);
633
634                 if (htype & BM_VERT) {
635                         for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
636                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
637                                         ((BMHeader **)output->data.p)[i] = e;
638                                         i++;
639                                 }
640                         }
641                 }
642
643                 if (htype & BM_EDGE) {
644                         for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
645                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
646                                         ((BMHeader **)output->data.p)[i] = e;
647                                         i++;
648                                 }
649                         }
650                 }
651
652                 if (htype & BM_FACE) {
653                         for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
654                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
655                                         ((BMHeader **)output->data.p)[i] = e;
656                                         i++;
657                                 }
658                         }
659                 }
660         }
661         else {
662                 output->len = 0;
663         }
664 }
665
666 /*
667  * BMO_FLAG_TO_SLOT
668  *
669  * Copies elements of a certain type, which have a certain flag set
670  * into an output slot for an operator.
671  */
672 void BMO_slot_from_flag(BMesh *bm, BMOperator *op, const char *slotname,
673                         const short oflag, const char htype)
674 {
675         BMIter elements;
676         BMHeader *e;
677         BMOpSlot *output = BMO_slot_get(op, slotname);
678         int totelement = BMO_mesh_flag_count(bm, oflag, htype), i = 0;
679
680         if (totelement) {
681                 bmo_slot_buffer_alloc(op, slotname, totelement);
682
683                 if (htype & BM_VERT) {
684                         for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
685                                 if (BMO_elem_flag_test(bm, e, oflag)) {
686                                         ((BMHeader **)output->data.p)[i] = e;
687                                         i++;
688                                 }
689                         }
690                 }
691
692                 if (htype & BM_EDGE) {
693                         for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
694                                 if (BMO_elem_flag_test(bm, e, oflag)) {
695                                         ((BMHeader **)output->data.p)[i] = e;
696                                         i++;
697                                 }
698                         }
699                 }
700
701                 if (htype & BM_FACE) {
702                         for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
703                                 if (BMO_elem_flag_test(bm, e, oflag)) {
704                                         ((BMHeader **)output->data.p)[i] = e;
705                                         i++;
706                                 }
707                         }
708                 }
709         }
710         else {
711                 output->len = 0;
712         }
713 }
714
715 /*
716  *
717  * BMO_FLAG_BUFFER
718  *
719  * Header Flags elements in a slots buffer, automatically
720  * using the selection API where appropriate.
721  */
722 void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slotname,
723                                   const char hflag, const char htype)
724 {
725         BMOpSlot *slot = BMO_slot_get(op, slotname);
726         BMHeader **data =  slot->data.p;
727         int i;
728         
729         for (i = 0; i < slot->len; i++) {
730                 if (!(htype & data[i]->htype))
731                         continue;
732
733                 if (hflag & BM_ELEM_SELECT) {
734                         BM_elem_select_set(bm, data[i], TRUE);
735                 }
736                 BM_elem_flag_enable(data[i], hflag);
737         }
738 }
739
740 /*
741  *
742  * BMO_FLAG_BUFFER
743  *
744  * Removes flags from elements in a slots buffer, automatically
745  * using the selection API where appropriate.
746  */
747 void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slotname,
748                                    const char hflag, const char htype)
749 {
750         BMOpSlot *slot = BMO_slot_get(op, slotname);
751         BMHeader **data =  slot->data.p;
752         int i;
753         
754         for (i = 0; i < slot->len; i++) {
755                 if (!(htype & data[i]->htype))
756                         continue;
757
758                 if (hflag & BM_ELEM_SELECT) {
759                         BM_elem_select_set(bm, data[i], FALSE);
760                 }
761
762                 BM_elem_flag_disable(data[i], hflag);
763         }
764 }
765 int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
766 {
767         int count = 0;
768
769         if (v->e) {
770                 BMEdge *curedge;
771                 const int len = bmesh_disk_count(v);
772                 int i;
773                 
774                 for (i = 0, curedge = v->e; i < len; i++) {
775                         if (BMO_elem_flag_test(bm, curedge, oflag))
776                                 count++;
777                         curedge = bmesh_disk_nextedge(curedge, v);
778                 }
779         }
780
781         return count;
782 }
783
784 /*
785  *
786  * BMO_FLAG_BUFFER
787  *
788  * Flags elements in a slots buffer
789  */
790 void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slotname,
791                           const short oflag, const char htype)
792 {
793         BMOpSlot *slot = BMO_slot_get(op, slotname);
794         BMHeader **data =  slot->data.p;
795         int i;
796         
797         for (i = 0; i < slot->len; i++) {
798                 if (!(htype & data[i]->htype))
799                         continue;
800
801                 BMO_elem_flag_enable(bm, data[i], oflag);
802         }
803 }
804
805 /*
806  *
807  * BMO_FLAG_BUFFER
808  *
809  * Removes flags from elements in a slots buffer
810  */
811 void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slotname,
812                                 const short oflag, const char htype)
813 {
814         BMOpSlot *slot = BMO_slot_get(op, slotname);
815         BMHeader **data =  slot->data.p;
816         int i;
817         
818         for (i = 0; i < slot->len; i++) {
819                 if (!(htype & data[i]->htype))
820                         continue;
821
822                 BMO_elem_flag_disable(bm, data[i], oflag);
823         }
824 }
825
826
827 /*
828  *
829  *      ALLOC/FREE FLAG LAYER
830  *
831  *  Used by operator stack to free/allocate
832  *  private flag data. This is allocated
833  *  using a mempool so the allocation/frees
834  *  should be quite fast.
835  *
836  *  BMESH_TODO:
837  *      Investigate not freeing flag layers until
838  *  all operators have been executed. This would
839  *  save a lot of realloc potentially.
840  */
841 static void bmo_flag_layer_alloc(BMesh *bm)
842 {
843         BMHeader *ele;
844         /* set the index values since we are looping over all data anyway,
845          * may save time later on */
846         int i;
847
848         BMIter iter;
849         BLI_mempool *oldpool = bm->toolflagpool;                /* old flag pool */
850         BLI_mempool *newpool;
851         void *oldflags;
852
853         /* store memcpy size for reuse */
854         const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
855         
856         bm->totflags++;
857
858         /* allocate new flag poo */
859         bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, FALSE, FALSE);
860         
861         /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
862         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
863                 oldflags = ele->flags;
864                 ele->flags = BLI_mempool_calloc(newpool);
865                 memcpy(ele->flags, oldflags, old_totflags_size);
866                 BM_elem_index_set(ele, i); /* set_inline */
867         }
868         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
869                 oldflags = ele->flags;
870                 ele->flags = BLI_mempool_calloc(newpool);
871                 memcpy(ele->flags, oldflags, old_totflags_size);
872                 BM_elem_index_set(ele, i); /* set_inline */
873         }
874         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
875                 oldflags = ele->flags;
876                 ele->flags = BLI_mempool_calloc(newpool);
877                 memcpy(ele->flags, oldflags, old_totflags_size);
878                 BM_elem_index_set(ele, i); /* set_inline */
879         }
880
881         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
882
883         BLI_mempool_destroy(oldpool);
884 }
885
886 static void bmo_flag_layer_free(BMesh *bm)
887 {
888         BMHeader *ele;
889         /* set the index values since we are looping over all data anyway,
890          * may save time later on */
891         int i;
892
893         BMIter iter;
894         BLI_mempool *oldpool = bm->toolflagpool;
895         BLI_mempool *newpool;
896         void *oldflags;
897         
898         /* store memcpy size for reuse */
899         const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
900
901         /* de-increment the totflags first.. */
902         bm->totflags--;
903         /* allocate new flag poo */
904         bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, TRUE, FALSE);
905         
906         /* now go through and memcpy all the flag */
907         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
908                 oldflags = ele->flags;
909                 ele->flags = BLI_mempool_calloc(newpool);
910                 memcpy(ele->flags, oldflags, new_totflags_size);
911                 BM_elem_index_set(ele, i); /* set_inline */
912         }
913         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
914                 oldflags = ele->flags;
915                 ele->flags = BLI_mempool_calloc(newpool);
916                 memcpy(ele->flags, oldflags, new_totflags_size);
917                 BM_elem_index_set(ele, i); /* set_inline */
918         }
919         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
920                 oldflags = ele->flags;
921                 ele->flags = BLI_mempool_calloc(newpool);
922                 memcpy(ele->flags, oldflags, new_totflags_size);
923                 BM_elem_index_set(ele, i); /* set_inline */
924         }
925
926         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
927
928         BLI_mempool_destroy(oldpool);
929 }
930
931 static void bmo_flag_layer_clear(BMesh *bm)
932 {
933         BMHeader *ele;
934         /* set the index values since we are looping over all data anyway,
935          * may save time later on */
936         int i;
937
938         BMIter iter;
939         const int totflags_offset = bm->totflags - 1;
940
941         /* now go through and memcpy all the flag */
942         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
943                 memset(ele->flags + totflags_offset, 0, sizeof(BMFlagLayer));
944                 BM_elem_index_set(ele, i); /* set_inline */
945         }
946         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
947                 memset(ele->flags + totflags_offset, 0, sizeof(BMFlagLayer));
948                 BM_elem_index_set(ele, i); /* set_inline */
949         }
950         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
951                 memset(ele->flags + totflags_offset, 0, sizeof(BMFlagLayer));
952                 BM_elem_index_set(ele, i); /* set_inline */
953         }
954
955         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
956 }
957
958 void *BMO_slot_elem_first(BMOperator *op, const char *slotname)
959 {
960         BMOpSlot *slot = BMO_slot_get(op, slotname);
961         
962         if (slot->slottype != BMOP_OPSLOT_ELEMENT_BUF)
963                 return NULL;
964
965         return slot->data.buf ? *(void **)slot->data.buf : NULL;
966 }
967
968 void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
969                    const char *slotname, const char restrictmask)
970 {
971         BMOpSlot *slot = BMO_slot_get(op, slotname);
972
973         memset(iter, 0, sizeof(BMOIter));
974
975         iter->slot = slot;
976         iter->cur = 0;
977         iter->restrictmask = restrictmask;
978
979         if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
980                 if (iter->slot->data.ghash) {
981                         BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
982                 }
983                 else {
984                         return NULL;
985                 }
986         }
987
988         return BMO_iter_step(iter);
989 }
990
991 void *BMO_iter_step(BMOIter *iter)
992 {
993         if (iter->slot->slottype == BMOP_OPSLOT_ELEMENT_BUF) {
994                 BMHeader *h;
995
996                 if (iter->cur >= iter->slot->len) {
997                         return NULL;
998                 }
999
1000                 h = ((void **)iter->slot->data.buf)[iter->cur++];
1001                 while (!(iter->restrictmask & h->htype)) {
1002                         if (iter->cur >= iter->slot->len) {
1003                                 return NULL;
1004                         }
1005
1006                         h = ((void **)iter->slot->data.buf)[iter->cur++];
1007                 }
1008
1009                 return h;
1010         }
1011         else if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
1012                 struct BMOElemMapping *map;
1013                 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1014                 map = BLI_ghashIterator_getValue(&iter->giter);
1015                 
1016                 iter->val = map + 1;
1017
1018                 BLI_ghashIterator_step(&iter->giter);
1019
1020                 return ret;
1021         }
1022
1023         return NULL;
1024 }
1025
1026 /* used for iterating over mapping */
1027 void *BMO_iter_map_value(BMOIter *iter)
1028 {
1029         return iter->val;
1030 }
1031
1032 void *BMO_iter_map_value_p(BMOIter *iter)
1033 {
1034         return *((void **)iter->val);
1035 }
1036
1037 float BMO_iter_map_value_f(BMOIter *iter)
1038 {
1039         return *((float *)iter->val);
1040 }
1041
1042 /* error syste */
1043 typedef struct BMOpError {
1044         struct BMOpError *next, *prev;
1045         int errorcode;
1046         BMOperator *op;
1047         const char *msg;
1048 } BMOpError;
1049
1050 void BMO_error_clear(BMesh *bm)
1051 {
1052         while (BMO_error_pop(bm, NULL, NULL));
1053 }
1054
1055 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1056 {
1057         BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1058         
1059         err->errorcode = errcode;
1060         if (!msg) msg = bmo_error_messages[errcode];
1061         err->msg = msg;
1062         err->op = owner;
1063         
1064         BLI_addhead(&bm->errorstack, err);
1065 }
1066
1067 int BMO_error_occurred(BMesh *bm)
1068 {
1069         return bm->errorstack.first != NULL;
1070 }
1071
1072 /* returns error code or 0 if no erro */
1073 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1074 {
1075         BMOpError *err = bm->errorstack.first;
1076         if (!err) {
1077                 return 0;
1078         }
1079
1080         if (msg) *msg = err->msg;
1081         if (op) *op = err->op;
1082         
1083         return err->errorcode;
1084 }
1085
1086 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1087 {
1088         int errorcode = BMO_error_get(bm, msg, op);
1089         
1090         if (errorcode) {
1091                 BMOpError *err = bm->errorstack.first;
1092                 
1093                 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1094                 MEM_freeN(err);
1095         }
1096
1097         return errorcode;
1098 }
1099
1100 /* example:
1101  * BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_ELEM_SELECT);
1102  *
1103  *  d - int
1104  *  i - int
1105  *  f - float
1106  *  hv - header flagged verts
1107  *  he - header flagged edges
1108  *  hf - header flagged faces
1109  *  fv - flagged verts
1110  *  fe - flagged edges
1111  *  ff - flagged faces
1112  */
1113
1114 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1115
1116 static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name)
1117 {
1118         int i;
1119
1120         for (i = 0; def->slottypes[i].type; i++) {
1121                 if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
1122                         return i;
1123                 }
1124         }
1125
1126         return -1;
1127 }
1128
1129 static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name)
1130 {
1131         int i = bmesh_name_to_slotcode(def, name);
1132         if (i < 0) {
1133                 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1134         }
1135
1136         return i;
1137 }
1138
1139 static int bmesh_opname_to_opcode(const char *opname)
1140 {
1141         int i;
1142
1143         for (i = 0; i < bmesh_total_ops; i++) {
1144                 if (!strcmp(opname, opdefines[i]->name)) {
1145                         return i;
1146                 }
1147         }
1148
1149         fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1150         return -1;
1151 }
1152
1153 int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1154 {
1155         BMOpDefine *def;
1156         char *opname, *ofmt, *fmt;
1157         char slotname[64] = {0};
1158         int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, ret, type, state;
1159         int noslot = 0;
1160
1161
1162         /* basic useful info to help find where bmop formatting strings fail */
1163         int lineno = -1;
1164 #   define GOTO_ERROR { lineno = __LINE__; goto error; }
1165
1166
1167         /* we muck around in here, so dup i */
1168         fmt = ofmt = BLI_strdup(_fmt);
1169         
1170         /* find operator nam */
1171         i = strcspn(fmt, " \t");
1172
1173         opname = fmt;
1174         if (!opname[i]) noslot = 1;
1175         opname[i] = '\0';
1176
1177         fmt += i + (noslot ? 0 : 1);
1178         
1179         i = bmesh_opname_to_opcode(opname);
1180
1181         if (i == -1) {
1182                 MEM_freeN(ofmt);
1183                 return FALSE;
1184         }
1185
1186         BMO_op_init(bm, op, opname);
1187         def = opdefines[i];
1188         
1189         i = 0;
1190         state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1191
1192         while (*fmt) {
1193                 if (state) {
1194                         /* jump past leading whitespac */
1195                         i = strspn(fmt, " \t");
1196                         fmt += i;
1197                         
1198                         /* ignore trailing whitespac */
1199                         if (!fmt[i])
1200                                 break;
1201
1202                         /* find end of slot name.  currently this is
1203                          * a little flexible, allowing "slot=%f",
1204                          * "slot %f", "slot%f", and "slot\t%f". */
1205                         i = strcspn(fmt, "= \t%");
1206                         if (!fmt[i]) GOTO_ERROR;
1207
1208                         fmt[i] = 0;
1209
1210                         if (bmesh_name_to_slotcode_check(def, fmt) < 0) GOTO_ERROR;
1211                         
1212                         BLI_strncpy(slotname, fmt, sizeof(slotname));
1213                         
1214                         state = 0;
1215                         fmt += i;
1216                 }
1217                 else {
1218                         switch (*fmt) {
1219                                 case ' ':
1220                                 case '\t':
1221                                 case '=':
1222                                 case '%':
1223                                         break;
1224                                 case 'm': {
1225                                         int size, c;
1226
1227                                         c = NEXT_CHAR(fmt);
1228                                         fmt++;
1229
1230                                         if (c == '3') size = 3;
1231                                         else if (c == '4') size = 4;
1232                                         else GOTO_ERROR;
1233
1234                                         BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
1235                                         state = 1;
1236                                         break;
1237                                 }
1238                                 case 'v': {
1239                                         BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
1240                                         state = 1;
1241                                         break;
1242                                 }
1243                                 case 'e': {
1244                                         BMHeader *ele = va_arg(vlist, void *);
1245                                         BMOpSlot *slot = BMO_slot_get(op, slotname);
1246
1247                                         slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1248                                         slot->len = 1;
1249                                         *((void **)slot->data.buf) = ele;
1250
1251                                         state = 1;
1252                                         break;
1253                                 }
1254                                 case 's': {
1255                                         BMOperator *op2 = va_arg(vlist, void *);
1256                                         const char *slotname2 = va_arg(vlist, char *);
1257
1258                                         BMO_slot_copy(op2, op, slotname2, slotname);
1259                                         state = 1;
1260                                         break;
1261                                 }
1262                                 case 'i':
1263                                 case 'd':
1264                                         BMO_slot_int_set(op, slotname, va_arg(vlist, int));
1265                                         state = 1;
1266                                         break;
1267                                 case 'p':
1268                                         BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
1269                                         state = 1;
1270                                         break;
1271                                 case 'f':
1272                                 case 'h':
1273                                 case 'a':
1274                                         type = *fmt;
1275
1276                                         if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\t' || NEXT_CHAR(fmt) == '\0') {
1277                                                 BMO_slot_float_set(op, slotname, va_arg(vlist, double));
1278                                         }
1279                                         else {
1280                                                 ret = 0;
1281                                                 stop = 0;
1282                                                 while (1) {
1283                                                         switch (NEXT_CHAR(fmt)) {
1284                                                                 case 'f': ret |= BM_FACE; break;
1285                                                                 case 'e': ret |= BM_EDGE; break;
1286                                                                 case 'v': ret |= BM_VERT; break;
1287                                                                 default:
1288                                                                         stop = 1;
1289                                                                         break;
1290                                                         }
1291                                                         if (stop) {
1292                                                                 break;
1293                                                         }
1294
1295                                                         fmt++;
1296                                                 }
1297
1298                                                 if (type == 'h') {
1299                                                         BMO_slot_from_hflag(bm, op, slotname, va_arg(vlist, int), ret);
1300                                                 }
1301                                                 else if (type == 'a') {
1302                                                         BMO_slot_from_all(bm, op, slotname, ret);
1303                                                 }
1304                                                 else {
1305                                                         BMO_slot_from_flag(bm, op, slotname, va_arg(vlist, int), ret);
1306                                                 }
1307                                         }
1308
1309                                         state = 1;
1310                                         break;
1311                                 default:
1312                                         fprintf(stderr,
1313                                                 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1314                                                 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1315                                         break;
1316                         }
1317                 }
1318                 fmt++;
1319         }
1320
1321         MEM_freeN(ofmt);
1322         return TRUE;
1323 error:
1324
1325         /* non urgent todo - explain exactly what is failing */
1326         fprintf(stderr,
1327                 "%s: error parsing formatting string, %d in '%s'\n    see - %s:%d\n",
1328                 __func__, (int)(fmt - ofmt), _fmt, __FILE__, lineno);
1329         MEM_freeN(ofmt);
1330
1331         BMO_op_finish(bm, op);
1332         return FALSE;
1333
1334 #undef GOTO_ERROR
1335
1336 }
1337
1338
1339 int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1340 {
1341         va_list list;
1342
1343         va_start(list, fmt);
1344         if (!BMO_op_vinitf(bm, op, fmt, list)) {
1345                 printf("%s: failed\n", __func__);
1346                 va_end(list);
1347                 return FALSE;
1348         }
1349         va_end(list);
1350
1351         return TRUE;
1352 }
1353
1354 int BMO_op_callf(BMesh *bm, const char *fmt, ...)
1355 {
1356         va_list list;
1357         BMOperator op;
1358
1359         va_start(list, fmt);
1360         if (!BMO_op_vinitf(bm, &op, fmt, list)) {
1361                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1362                 va_end(list);
1363                 return FALSE;
1364         }
1365
1366         BMO_op_exec(bm, &op);
1367         BMO_op_finish(bm, &op);
1368
1369         va_end(list);
1370         return TRUE;
1371 }
1372
1373 /*
1374  * BMO_TOGGLEFLAG
1375  *
1376  * Toggles a flag for a certain element
1377  */
1378 #ifdef BMO_elem_flag_toggle
1379 #undef BMO_elem_flag_toggle
1380 #endif
1381 static void BMO_elem_flag_toggle(BMesh *bm, void *element, const short oflag)
1382 {
1383         BMHeader *head = element;
1384         head->flags[bm->stackdepth - 1].f ^= oflag;
1385 }
1386
1387 /*
1388  * BMO_SETFLAG
1389  *
1390  * Sets a flag for a certain element
1391  */
1392 #ifdef BMO_elem_flag_enable
1393 #undef BMO_elem_flag_enable
1394 #endif
1395 static void BMO_elem_flag_enable(BMesh *bm, void *element, const short oflag)
1396 {
1397         BMHeader *head = element;
1398         head->flags[bm->stackdepth - 1].f |= oflag;
1399 }
1400
1401 /*
1402  * BMO_CLEARFLAG
1403  *
1404  * Clears a specific flag from a given element
1405  */
1406 #ifdef BMO_elem_flag_disable
1407 #undef BMO_elem_flag_disable
1408 #endif
1409 static void BMO_elem_flag_disable(BMesh *bm, void *element, const short oflag)
1410 {
1411         BMHeader *head = element;
1412         head->flags[bm->stackdepth - 1].f &= ~oflag;
1413 }
1414
1415 /*
1416  * BMO_TESTFLAG
1417  *
1418  * Tests whether or not a flag is set for a specific element
1419  *
1420  */
1421 #ifdef BMO_elem_flag_test
1422 #undef BMO_elem_flag_test
1423 #endif
1424 static int BMO_elem_flag_test(BMesh *bm, void *element, const short oflag)
1425 {
1426         BMHeader *head = element;
1427         if (head->flags[bm->stackdepth - 1].f & oflag)
1428                 return TRUE;
1429         return FALSE;
1430 }