svn merge ^/trunk/blender -r43976:43995
[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(BMOElemMapping)
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, const int op_flag)
85 {
86         op->flag |= op_flag;
87 }
88
89 void BMO_Clear_OpFlag(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
90 {
91         op->flag &= ~op_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                                 const int slot_alloc_size = BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
270                                 dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
271                                 memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
272                         }
273                 }
274                 else {
275                         GHashIterator it;
276                         BMOElemMapping *srcmap, *dstmap;
277
278                         /* sanity check */
279                         if (!source_slot->data.ghash) return;
280                         
281                         if (!dest_slot->data.ghash) {
282                                 dest_slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
283                                                                       BLI_ghashutil_ptrcmp, "bmesh operator 2");
284                         }
285
286                         BLI_ghashIterator_init(&it, source_slot->data.ghash);
287                         for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
288                               BLI_ghashIterator_step(&it))
289                         {
290                                 dstmap = BLI_memarena_alloc(dest_op->arena, 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, dstmap->element, dstmap);
297                         }
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 void BMO_Set_Float(BMOperator *op, const char *slotname, float f)
313 {
314         BMOpSlot *slot = BMO_GetSlot(op, slotname);
315         if (!(slot->slottype == BMOP_OPSLOT_FLT))
316                 return;
317
318         slot->data.f = f;
319 }
320
321 void BMO_Set_Int(BMOperator *op, const char *slotname, int i)
322 {
323         BMOpSlot *slot = BMO_GetSlot(op, slotname);
324         if (!(slot->slottype == BMOP_OPSLOT_INT))
325                 return;
326
327         slot->data.i = i;
328 }
329
330 /* only supports square mats */
331 void BMO_Set_Mat(struct BMOperator *op, const char *slotname, float *mat, int size)
332 {
333         BMOpSlot *slot = BMO_GetSlot(op, slotname);
334         if (!(slot->slottype == BMOP_OPSLOT_MAT))
335                 return;
336
337         slot->len = 4;
338         slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
339         
340         if (size == 4) {
341                 memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
342         }
343         else if (size == 3) {
344                 copy_m4_m3(slot->data.p, (float (*)[3])mat);
345         }
346         else {
347                 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
348
349                 memset(slot->data.p, 0, sizeof(float) * 4 * 4);
350                 return;
351         }
352 }
353
354 void BMO_Get_Mat4(struct BMOperator *op, const char *slotname, float mat[4][4])
355 {
356         BMOpSlot *slot = BMO_GetSlot(op, slotname);
357         if (!(slot->slottype == BMOP_OPSLOT_MAT))
358                 return;
359
360         memcpy(mat, slot->data.p, sizeof(float) * 4 * 4);
361 }
362
363 void BMO_Get_Mat3(struct BMOperator *op, const char *slotname, float mat[3][3])
364 {
365         BMOpSlot *slot = BMO_GetSlot(op, slotname);
366         if (!(slot->slottype == BMOP_OPSLOT_MAT))
367                 return;
368
369         copy_m3_m4(mat, slot->data.p);
370 }
371
372 void BMO_Set_Pnt(BMOperator *op, const char *slotname, void *p)
373 {
374         BMOpSlot *slot = BMO_GetSlot(op, slotname);
375         if (!(slot->slottype == BMOP_OPSLOT_PNT))
376                 return;
377
378         slot->data.p = p;
379 }
380
381 void BMO_Set_Vec(BMOperator *op, const char *slotname, const float vec[3])
382 {
383         BMOpSlot *slot = BMO_GetSlot(op, slotname);
384         if (!(slot->slottype == BMOP_OPSLOT_VEC))
385                 return;
386
387         copy_v3_v3(slot->data.vec, vec);
388 }
389
390
391 float BMO_Get_Float(BMOperator *op, const char *slotname)
392 {
393         BMOpSlot *slot = BMO_GetSlot(op, slotname);
394         if (!(slot->slottype == BMOP_OPSLOT_FLT))
395                 return 0.0f;
396
397         return slot->data.f;
398 }
399
400 int BMO_Get_Int(BMOperator *op, const char *slotname)
401 {
402         BMOpSlot *slot = BMO_GetSlot(op, slotname);
403         if (!(slot->slottype == BMOP_OPSLOT_INT))
404                 return 0;
405
406         return slot->data.i;
407 }
408
409
410 void *BMO_Get_Pnt(BMOperator *op, const char *slotname)
411 {
412         BMOpSlot *slot = BMO_GetSlot(op, slotname);
413         if (!(slot->slottype == BMOP_OPSLOT_PNT))
414                 return NULL;
415
416         return slot->data.p;
417 }
418
419 void BMO_Get_Vec(BMOperator *op, const char *slotname, float r_vec[3])
420 {
421         BMOpSlot *slot = BMO_GetSlot(op, slotname);
422         if (!(slot->slottype == BMOP_OPSLOT_VEC))
423                 return;
424
425         copy_v3_v3(r_vec, slot->data.vec);
426 }
427
428 /*
429  * BMO_COUNTFLAG
430  *
431  * Counts the number of elements of a certain type that
432  * have a specific flag set.
433  *
434  */
435
436 int BMO_CountFlag(BMesh *bm, const short oflag, const char htype)
437 {
438         BMIter elements;
439         BMHeader *e;
440         int count = 0;
441
442         if (htype & BM_VERT) {
443                 for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
444                         if (BMO_TestFlag(bm, e, oflag))
445                                 count++;
446                 }
447         }
448         if (htype & BM_EDGE) {
449                 for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
450                         if (BMO_TestFlag(bm, e, oflag))
451                                 count++;
452                 }
453         }
454         if (htype & BM_FACE) {
455                 for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
456                         if (BMO_TestFlag(bm, e, oflag))
457                                 count++;
458                 }
459         }
460
461         return count;
462 }
463
464 void BMO_Clear_Flag_All(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
465 {
466         const char iter_types[3] = {BM_VERTS_OF_MESH,
467                                     BM_EDGES_OF_MESH,
468                                     BM_FACES_OF_MESH};
469
470         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
471
472         BMIter iter;
473         BMHeader *ele;
474         int i;
475
476         for (i = 0; i < 3; i++) {
477                 if (htype & flag_types[i]) {
478                         BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
479                                 BMO_ClearFlag(bm, ele, oflag);
480                         }
481                 }
482         }
483 }
484
485 int BMO_CountSlotBuf(struct BMesh *UNUSED(bm), struct BMOperator *op, const char *slotname)
486 {
487         BMOpSlot *slot = BMO_GetSlot(op, slotname);
488         
489         /* check if its actually a buffer */
490         if (!(slot->slottype > BMOP_OPSLOT_VEC))
491                 return 0;
492
493         return slot->len;
494 }
495
496 int BMO_CountSlotMap(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
497 {
498         BMOpSlot *slot = BMO_GetSlot(op, slotname);
499         
500         /* check if its actually a buffer */
501         if (!(slot->slottype == BMOP_OPSLOT_MAPPING))
502                 return 0;
503
504         return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
505 }
506
507 #if 0
508 void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd)
509 {
510         BMOpSlot *slot = &op->slots[slotcode];
511         void *tmp;
512         
513         /* check if its actually a buffer */
514         if (!(slot->slottype > BMOP_OPSLOT_VEC))
515                 return NULL;
516
517         if (slot->flag & BMOS_DYNAMIC_ARRAY) {
518                 if (slot->len >= slot->size) {
519                         slot->size = (slot->size + 1 + totadd) * 2;
520
521                         tmp = slot->data.buf;
522                         slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size, "opslot dynamic array");
523                         memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size);
524                         MEM_freeN(tmp);
525                 }
526
527                 slot->len += totadd;
528         }
529         else {
530                 slot->flag |= BMOS_DYNAMIC_ARRAY;
531                 slot->len += totadd;
532                 slot->size = slot->len + 2;
533                 tmp = slot->data.buf;
534                 slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len, "opslot dynamic array");
535                 memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len);
536         }
537
538         return slot->data.buf;
539 }
540 #endif
541
542 void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op,
543                          const char *slotname, const short oflag)
544 {
545         GHashIterator it;
546         BMOpSlot *slot = BMO_GetSlot(op, slotname);
547         BMHeader *ele;
548
549         /* sanity check */
550         if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
551         if (!slot->data.ghash) return;
552
553         BLI_ghashIterator_init(&it, slot->data.ghash);
554         for ( ; (ele = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
555                 BMO_SetFlag(bm, ele, oflag);
556         }
557 }
558
559 static void *alloc_slot_buffer(BMOperator *op, const char *slotname, int len)
560 {
561         BMOpSlot *slot = BMO_GetSlot(op, slotname);
562
563         /* check if its actually a buffer */
564         if (!(slot->slottype > BMOP_OPSLOT_VEC))
565                 return NULL;
566         
567         slot->len = len;
568         if (len)
569                 slot->data.buf = BLI_memarena_alloc(op->arena, BMOP_OPSLOT_TYPEINFO[slot->slottype] * len);
570         return slot->data.buf;
571 }
572
573 /*
574  * BMO_ALL_TO_SLOT
575  *
576  * Copies all elements of a certain type into an operator slot.
577  *
578  */
579
580 static void BMO_All_To_Slot(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
581 {
582         BMIter elements;
583         BMHeader *e;
584         BMOpSlot *output = BMO_GetSlot(op, slotname);
585         int totelement = 0, i = 0;
586         
587         if (htype & BM_VERT) totelement += bm->totvert;
588         if (htype & BM_EDGE) totelement += bm->totedge;
589         if (htype & BM_FACE) totelement += bm->totface;
590
591         if (totelement) {
592                 alloc_slot_buffer(op, slotname, totelement);
593
594                 if (htype & BM_VERT) {
595                         for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
596                                 ((BMHeader **)output->data.p)[i] = e;
597                                 i++;
598                         }
599                 }
600
601                 if (htype & BM_EDGE) {
602                         for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
603                                 ((BMHeader **)output->data.p)[i] = e;
604                                 i++;
605                         }
606                 }
607
608                 if (htype & BM_FACE) {
609                         for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
610                                 ((BMHeader **)output->data.p)[i] = e;
611                                 i++;
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 void BMO_HeaderFlag_To_Slot(BMesh *bm, BMOperator *op, const char *slotname,
625                             const char hflag, const char htype)
626 {
627         BMIter elements;
628         BMHeader *e;
629         BMOpSlot *output = BMO_GetSlot(op, slotname);
630         int totelement = 0, i = 0;
631         
632         totelement = BM_CountFlag(bm, htype, hflag, 1);
633
634         if (totelement) {
635                 alloc_slot_buffer(op, slotname, totelement);
636
637                 if (htype & BM_VERT) {
638                         for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
639                                 if (!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, hflag)) {
640                                         ((BMHeader **)output->data.p)[i] = e;
641                                         i++;
642                                 }
643                         }
644                 }
645
646                 if (htype & BM_EDGE) {
647                         for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
648                                 if (!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, hflag)) {
649                                         ((BMHeader **)output->data.p)[i] = e;
650                                         i++;
651                                 }
652                         }
653                 }
654
655                 if (htype & BM_FACE) {
656                         for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
657                                 if (!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, hflag)) {
658                                         ((BMHeader **)output->data.p)[i] = e;
659                                         i++;
660                                 }
661                         }
662                 }
663         }
664         else {
665                 output->len = 0;
666         }
667 }
668
669 /*
670  * BMO_FLAG_TO_SLOT
671  *
672  * Copies elements of a certain type, which have a certain flag set
673  * into an output slot for an operator.
674  */
675 void BMO_Flag_To_Slot(BMesh *bm, BMOperator *op, const char *slotname,
676                       const short oflag, const char htype)
677 {
678         BMIter elements;
679         BMHeader *e;
680         BMOpSlot *output = BMO_GetSlot(op, slotname);
681         int totelement = BMO_CountFlag(bm, oflag, htype), i = 0;
682
683         if (totelement) {
684                 alloc_slot_buffer(op, slotname, totelement);
685
686                 if (htype & BM_VERT) {
687                         for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
688                                 if (BMO_TestFlag(bm, e, oflag)) {
689                                         ((BMHeader **)output->data.p)[i] = e;
690                                         i++;
691                                 }
692                         }
693                 }
694
695                 if (htype & BM_EDGE) {
696                         for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
697                                 if (BMO_TestFlag(bm, e, oflag)) {
698                                         ((BMHeader **)output->data.p)[i] = e;
699                                         i++;
700                                 }
701                         }
702                 }
703
704                 if (htype & BM_FACE) {
705                         for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
706                                 if (BMO_TestFlag(bm, e, oflag)) {
707                                         ((BMHeader **)output->data.p)[i] = e;
708                                         i++;
709                                 }
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, const short oflag)
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, oflag))
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 short oflag, 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], oflag);
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 short oflag, 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], oflag);
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 poo */
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 poo */
907         bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, TRUE, FALSE);
908         
909         /* now go through and memcpy all the flag */
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         BMHeader *ele;
937         /* set the index values since we are looping over all data anyway,
938          * may save time later on */
939         int i;
940
941         BMIter iter;
942         const int totflags_offset = bm->totflags - 1;
943
944         /* now go through and memcpy all the flag */
945         for (ele = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BMIter_Step(&iter), i++) {
946                 memset(ele->flags + totflags_offset, 0, sizeof(BMFlagLayer));
947                 BM_SetIndex(ele, i); /* set_inline */
948         }
949         for (ele = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BMIter_Step(&iter), i++) {
950                 memset(ele->flags + totflags_offset, 0, sizeof(BMFlagLayer));
951                 BM_SetIndex(ele, i); /* set_inline */
952         }
953         for (ele = BMIter_New(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BMIter_Step(&iter), i++) {
954                 memset(ele->flags + totflags_offset, 0, sizeof(BMFlagLayer));
955                 BM_SetIndex(ele, i); /* set_inline */
956         }
957
958         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
959 }
960
961 void *BMO_FirstElem(BMOperator *op, const char *slotname)
962 {
963         BMOpSlot *slot = BMO_GetSlot(op, slotname);
964         
965         if (slot->slottype != BMOP_OPSLOT_ELEMENT_BUF)
966                 return NULL;
967
968         return slot->data.buf ? *(void **)slot->data.buf : NULL;
969 }
970
971 void *BMO_IterNew(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
972                   const char *slotname, const char restrictmask)
973 {
974         BMOpSlot *slot = BMO_GetSlot(op, slotname);
975
976         memset(iter, 0, sizeof(BMOIter));
977
978         iter->slot = slot;
979         iter->cur = 0;
980         iter->restrictmask = restrictmask;
981
982         if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
983                 if (iter->slot->data.ghash) {
984                         BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
985                 }
986                 else {
987                         return NULL;
988                 }
989         }
990
991         return BMO_IterStep(iter);
992 }
993
994 void *BMO_IterStep(BMOIter *iter)
995 {
996         if (iter->slot->slottype == BMOP_OPSLOT_ELEMENT_BUF) {
997                 BMHeader *h;
998
999                 if (iter->cur >= iter->slot->len) {
1000                         return NULL;
1001                 }
1002
1003                 h = ((void **)iter->slot->data.buf)[iter->cur++];
1004                 while (!(iter->restrictmask & h->htype)) {
1005                         if (iter->cur >= iter->slot->len) {
1006                                 return NULL;
1007                         }
1008
1009                         h = ((void **)iter->slot->data.buf)[iter->cur++];
1010                 }
1011
1012                 return h;
1013         }
1014         else if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
1015                 struct BMOElemMapping *map;
1016                 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1017                 map = BLI_ghashIterator_getValue(&iter->giter);
1018                 
1019                 iter->val = map + 1;
1020
1021                 BLI_ghashIterator_step(&iter->giter);
1022
1023                 return ret;
1024         }
1025
1026         return NULL;
1027 }
1028
1029 /* used for iterating over mapping */
1030 void *BMO_IterMapVal(BMOIter *iter)
1031 {
1032         return iter->val;
1033 }
1034
1035 void *BMO_IterMapValp(BMOIter *iter)
1036 {
1037         return *((void **)iter->val);
1038 }
1039
1040 float BMO_IterMapValf(BMOIter *iter)
1041 {
1042         return *((float *)iter->val);
1043 }
1044
1045 /* error syste */
1046 typedef struct BMOpError {
1047        struct BMOpError *next, *prev;
1048        int errorcode;
1049        BMOperator *op;
1050        const char *msg;
1051 } BMOpError;
1052
1053 void BMO_ClearStack(BMesh *bm)
1054 {
1055         while (BMO_PopError(bm, NULL, NULL));
1056 }
1057
1058 void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1059 {
1060         BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1061         
1062         err->errorcode = errcode;
1063         if (!msg) msg = bmop_error_messages[errcode];
1064         err->msg = msg;
1065         err->op = owner;
1066         
1067         BLI_addhead(&bm->errorstack, err);
1068 }
1069
1070 int BMO_HasError(BMesh *bm)
1071 {
1072         return bm->errorstack.first != NULL;
1073 }
1074
1075 /* returns error code or 0 if no erro */
1076 int BMO_GetError(BMesh *bm, const char **msg, BMOperator **op)
1077 {
1078         BMOpError *err = bm->errorstack.first;
1079         if (!err) {
1080                 return 0;
1081         }
1082
1083         if (msg) *msg = err->msg;
1084         if (op) *op = err->op;
1085         
1086         return err->errorcode;
1087 }
1088
1089 int BMO_PopError(BMesh *bm, const char **msg, BMOperator **op)
1090 {
1091         int errorcode = BMO_GetError(bm, msg, op);
1092         
1093         if (errorcode) {
1094                 BMOpError *err = bm->errorstack.first;
1095                 
1096                 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1097                 MEM_freeN(err);
1098         }
1099
1100         return errorcode;
1101 }
1102
1103 #if 0
1104 typedef struct BMOFlag {
1105         const char *str;
1106         int flag;
1107 } BMOFlag;
1108
1109 #define PAIR(f) {#f, f},fv
1110 static const char *bmesh_flags = {
1111         PAIR(BM_SELECT);
1112         PAIR(BM_SEAM);
1113         PAIR(BM_FGON);
1114         PAIR(BM_HIDDEN);
1115         PAIR(BM_SHARP);
1116         PAIR(BM_SMOOTH);
1117         {NULL, 0};
1118 };
1119 #undef PAIR
1120
1121 int bmesh_str_to_flag(const char *str)
1122 {
1123         int i;
1124
1125         while (bmesh_flags[i]->name) {
1126                 if (!strcmp(bmesh_flags[i]->name, str))
1127                         return bmesh_flags[i]->flag;
1128         }
1129
1130         return -1;
1131 }
1132 #endif
1133
1134 /* example:
1135  * BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_SELECT);
1136  *
1137  *  d - int
1138  *  i - int
1139  *  f - float
1140  *  hv - header flagged verts
1141  *  he - header flagged edges
1142  *  hf - header flagged faces
1143  *  fv - flagged verts
1144  *  fe - flagged edges
1145  *  ff - flagged faces
1146  */
1147
1148 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1149
1150 static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name)
1151 {
1152         int i;
1153
1154         for (i = 0; def->slottypes[i].type; i++) {
1155                 if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
1156                         return i;
1157                 }
1158         }
1159
1160         return -1;
1161 }
1162
1163 static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name)
1164 {
1165         int i = bmesh_name_to_slotcode(def, name);
1166         if (i < 0) {
1167                 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1168         }
1169
1170         return i;
1171 }
1172
1173 static int bmesh_opname_to_opcode(const char *opname)
1174 {
1175         int i;
1176
1177         for (i = 0; i < bmesh_total_ops; i++) {
1178                 if (!strcmp(opname, opdefines[i]->name)) {
1179                         return i;
1180                 }
1181         }
1182
1183         fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1184         return -1;
1185 }
1186
1187 int BMO_VInitOpf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1188 {
1189         BMOpDefine *def;
1190         char *opname, *ofmt, *fmt;
1191         char slotname[64] = {0};
1192         int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, ret, type, state;
1193         int noslot = 0;
1194
1195
1196         /* basic useful info to help find where bmop formatting strings fail */
1197         int lineno = -1;
1198 #   define GOTO_ERROR { lineno = __LINE__; goto error; }
1199
1200
1201         /* we muck around in here, so dup i */
1202         fmt = ofmt = BLI_strdup(_fmt);
1203         
1204         /* find operator nam */
1205         i = strcspn(fmt, " \t");
1206
1207         opname = fmt;
1208         if (!opname[i]) noslot = 1;
1209         opname[i] = '\0';
1210
1211         fmt += i + (noslot ? 0 : 1);
1212         
1213         i = bmesh_opname_to_opcode(opname);
1214
1215         if (i == -1) {
1216                 MEM_freeN(ofmt);
1217                 return FALSE;
1218         }
1219
1220         BMO_Init_Op(bm, op, opname);
1221         def = opdefines[i];
1222         
1223         i = 0;
1224         state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1225
1226         while (*fmt) {
1227                 if (state) {
1228                         /* jump past leading whitespac */
1229                         i = strspn(fmt, " \t");
1230                         fmt += i;
1231                         
1232                         /* ignore trailing whitespac */
1233                         if (!fmt[i])
1234                                 break;
1235
1236                         /* find end of slot name.  currently this is
1237                          * a little flexible, allowing "slot=%f",
1238                          * "slot %f", "slot%f", and "slot\t%f". */
1239                         i = strcspn(fmt, "= \t%");
1240                         if (!fmt[i]) GOTO_ERROR;
1241
1242                         fmt[i] = 0;
1243
1244                         if (bmesh_name_to_slotcode_check(def, fmt) < 0) GOTO_ERROR;
1245                         
1246                         BLI_strncpy(slotname, fmt, sizeof(slotname));
1247                         
1248                         state = 0;
1249                         fmt += i;
1250                 }
1251                 else {
1252                         switch (*fmt) {
1253                         case ' ':
1254                         case '\t':
1255                         case '=':
1256                         case '%':
1257                                 break;
1258                         case 'm': {
1259                                 int size, c;
1260                                 
1261                                 c = NEXT_CHAR(fmt);
1262                                 fmt++;
1263
1264                                 if (c == '3') size = 3;
1265                                 else if (c == '4') size = 4;
1266                                 else GOTO_ERROR;
1267
1268                                 BMO_Set_Mat(op, slotname, va_arg(vlist, void *), size);
1269                                 state = 1;
1270                                 break;
1271                         }
1272                         case 'v': {
1273                                 BMO_Set_Vec(op, slotname, va_arg(vlist, float *));
1274                                 state = 1;
1275                                 break;
1276                         }
1277                         case 'e': {
1278                                 BMHeader *ele = va_arg(vlist, void *);
1279                                 BMOpSlot *slot = BMO_GetSlot(op, slotname);
1280
1281                                 slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1282                                 slot->len = 1;
1283                                 *((void **)slot->data.buf) = ele;
1284
1285                                 state = 1;
1286                                 break;
1287                         }
1288                         case 's': {
1289                                 BMOperator *op2 = va_arg(vlist, void *);
1290                                 const char *slotname2 = va_arg(vlist, char *);
1291
1292                                 BMO_CopySlot(op2, op, slotname2, slotname);
1293                                 state = 1;
1294                                 break;
1295                         }
1296                         case 'i':
1297                         case 'd':
1298                                 BMO_Set_Int(op, slotname, va_arg(vlist, int));
1299                                 state = 1;
1300                                 break;
1301                         case 'p':
1302                                 BMO_Set_Pnt(op, slotname, va_arg(vlist, void *));
1303                                 state = 1;
1304                                 break;
1305                         case 'f':
1306                         case 'h':
1307                         case 'a':
1308                                 type = *fmt;
1309
1310                                 if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\t' || NEXT_CHAR(fmt) == '\0') {
1311                                         BMO_Set_Float(op, slotname, va_arg(vlist, double));
1312                                 }
1313                                 else {
1314                                         ret = 0;
1315                                         stop = 0;
1316                                         while (1) {
1317                                                 switch (NEXT_CHAR(fmt)) {
1318                                                         case 'f': ret |= BM_FACE; break;
1319                                                         case 'e': ret |= BM_EDGE; break;
1320                                                         case 'v': ret |= BM_VERT; break;
1321                                                         default:
1322                                                                 stop = 1;
1323                                                                 break;
1324                                                 }
1325                                                 if (stop) {
1326                                                         break;
1327                                                 }
1328
1329                                                 fmt++;
1330                                         }
1331
1332                                         if (type == 'h') {
1333                                                 BMO_HeaderFlag_To_Slot(bm, op, slotname, va_arg(vlist, int), ret);
1334                                         }
1335                                         else if (type == 'a') {
1336                                                 BMO_All_To_Slot(bm, op, slotname, ret);
1337                                         }
1338                                         else {
1339                                                 BMO_Flag_To_Slot(bm, op, slotname, va_arg(vlist, int), ret);
1340                                         }
1341                                 }
1342
1343                                 state = 1;
1344                                 break;
1345                         default:
1346                                 fprintf(stderr,
1347                                         "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1348                                         __func__, *fmt, (int)(fmt - ofmt), ofmt);
1349                                 break;
1350                         }
1351                 }
1352                 fmt++;
1353         }
1354
1355         MEM_freeN(ofmt);
1356         return TRUE;
1357 error:
1358
1359         /* non urgent todo - explain exactly what is failing */
1360         fprintf(stderr,
1361                 "%s: error parsing formatting string, %d in '%s'\n    see - %s:%d\n",
1362                 __func__, (int)(fmt - ofmt), _fmt, __FILE__, lineno);
1363         MEM_freeN(ofmt);
1364
1365         BMO_Finish_Op(bm, op);
1366         return FALSE;
1367
1368 #undef GOTO_ERROR
1369
1370 }
1371
1372
1373 int BMO_InitOpf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1374 {
1375         va_list list;
1376
1377         va_start(list, fmt);
1378         if (!BMO_VInitOpf(bm, op, fmt, list)) {
1379                 printf("%s: failed\n", __func__);
1380                 va_end(list);
1381                 return FALSE;
1382         }
1383         va_end(list);
1384
1385         return TRUE;
1386 }
1387
1388 int BMO_CallOpf(BMesh *bm, const char *fmt, ...)
1389 {
1390         va_list list;
1391         BMOperator op;
1392
1393         va_start(list, fmt);
1394         if (!BMO_VInitOpf(bm, &op, fmt, list)) {
1395                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1396                 va_end(list);
1397                 return FALSE;
1398         }
1399
1400         BMO_Exec_Op(bm, &op);
1401         BMO_Finish_Op(bm, &op);
1402
1403         va_end(list);
1404         return TRUE;
1405 }
1406
1407 /*
1408  * BMO_TOGGLEFLAG
1409  *
1410  * Toggles a flag for a certain element
1411  */
1412 #ifdef BMO_ToggleFlag
1413 #undef BMO_ToggleFlag
1414 #endif
1415 static void BMO_ToggleFlag(BMesh *bm, void *element, const short oflag)
1416 {
1417         BMHeader *head = element;
1418         head->flags[bm->stackdepth - 1].f ^= oflag;
1419 }
1420
1421 /*
1422  * BMO_SETFLAG
1423  *
1424  * Sets a flag for a certain element
1425  */
1426 #ifdef BMO_SetFlag
1427 #undef BMO_SetFlag
1428 #endif
1429 static void BMO_SetFlag(BMesh *bm, void *element, const short oflag)
1430 {
1431         BMHeader *head = element;
1432         head->flags[bm->stackdepth - 1].f |= oflag;
1433 }
1434
1435 /*
1436  * BMO_CLEARFLAG
1437  *
1438  * Clears a specific flag from a given element
1439  */
1440 #ifdef BMO_ClearFlag
1441 #undef BMO_ClearFlag
1442 #endif
1443 static void BMO_ClearFlag(BMesh *bm, void *element, const short oflag)
1444 {
1445         BMHeader *head = element;
1446         head->flags[bm->stackdepth - 1].f &= ~oflag;
1447 }
1448
1449 /*
1450  * BMO_TESTFLAG
1451  *
1452  * Tests whether or not a flag is set for a specific element
1453  *
1454  */
1455 #ifdef BMO_TestFlag
1456 #undef BMO_TestFlag
1457 #endif
1458 static int BMO_TestFlag(BMesh *bm, void *element, const short oflag)
1459 {
1460         BMHeader *head = element;
1461         if (head->flags[bm->stackdepth - 1].f & oflag)
1462                 return TRUE;
1463         return FALSE;
1464 }