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