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