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