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