bmesh iterators were passing the BMesh as data argument to BM_iter_new(), harmless...
[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 "intern/bmesh_private.h"
41
42 /* forward declarations */
43 static void bmo_flag_layer_alloc(BMesh *bm);
44 static void bmo_flag_layer_free(BMesh *bm);
45 static void bmo_flag_layer_clear(BMesh *bm);
46 static int bmo_name_to_slotcode(BMOpDefine *def, const char *name);
47 static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name);
48 static int bmo_opname_to_opcode(const char *opname);
49
50 static const char *bmo_error_messages[] = {
51         NULL,
52         "Self intersection error",
53         "Could not dissolve vert",
54         "Could not connect vertices",
55         "Could not traverse mesh",
56         "Could not dissolve faces",
57         "Could not dissolve vertices",
58         "Tessellation error",
59         "Can not deal with non-manifold geometry",
60         "Invalid selection",
61         "Internal mesh error",
62 };
63
64
65 /* operator slot type information - size of one element of the type given. */
66 const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = {
67         0,                      /*  0: BMO_OP_SLOT_SENTINEL */
68         sizeof(int),            /*  1: BMO_OP_SLOT_BOOL */ 
69         sizeof(int),            /*  2: BMO_OP_SLOT_INT */ 
70         sizeof(float),          /*  3: BMO_OP_SLOT_FLT */ 
71         sizeof(void *),         /*  4: BMO_OP_SLOT_PNT */ 
72         sizeof(void *),         /*  5: BMO_OP_SLOT_PNT */
73         0,                      /*  6: unused */
74         0,                      /*  7: unused */
75         sizeof(float) * 3,      /*  8: BMO_OP_SLOT_VEC */
76         sizeof(void *),         /*  9: BMO_OP_SLOT_ELEMENT_BUF */
77         sizeof(BMOElemMapping)  /* 10: BMO_OP_SLOT_MAPPING */
78 };
79
80 /* Dummy slot so there is something to return when slot name lookup fails */
81 static BMOpSlot BMOpEmptySlot = {0};
82
83 void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
84 {
85         op->flag |= op_flag;
86 }
87
88 void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
89 {
90         op->flag &= ~op_flag;
91 }
92
93 /**
94  * \brief BMESH OPSTACK PUSH
95  *
96  * Pushes the opstack down one level and allocates a new flag layer if appropriate.
97  */
98 void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
99 {
100         bm->stackdepth++;
101
102         /* add flag layer, if appropriate */
103         if (bm->stackdepth > 1)
104                 bmo_flag_layer_alloc(bm);
105         else
106                 bmo_flag_layer_clear(bm);
107 }
108
109 /**
110  * \brief BMESH OPSTACK POP
111  *
112  * Pops the opstack one level and frees a flag layer if appropriate
113  *
114  * BMESH_TODO: investigate NOT freeing flag layers.
115  */
116 void BMO_pop(BMesh *bm)
117 {
118         if (bm->stackdepth > 1)
119                 bmo_flag_layer_free(bm);
120
121         bm->stackdepth--;
122 }
123
124 /**
125  * \brief BMESH OPSTACK INIT OP
126  *
127  * Initializes an operator structure to a certain type
128  */
129 void BMO_op_init(BMesh *bm, BMOperator *op, const char *opname)
130 {
131         int i, opcode = bmo_opname_to_opcode(opname);
132
133 #ifdef DEBUG
134         BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
135 #else
136         (void)bm;
137 #endif
138
139         if (opcode == -1) {
140                 opcode = 0; /* error!, already printed, have a better way to handle this? */
141         }
142
143         memset(op, 0, sizeof(BMOperator));
144         op->type = opcode;
145         op->flag = opdefines[opcode]->flag;
146         
147         /* initialize the operator slot types */
148         for (i = 0; opdefines[opcode]->slottypes[i].type; i++) {
149                 op->slots[i].slottype = opdefines[opcode]->slottypes[i].type;
150                 op->slots[i].index = i;
151         }
152
153         /* callback */
154         op->exec = opdefines[opcode]->exec;
155
156         /* memarena, used for operator's slot buffers */
157         op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
158         BLI_memarena_use_calloc(op->arena);
159 }
160
161 /**
162  * \brief BMESH OPSTACK EXEC OP
163  *
164  * Executes a passed in operator.
165  *
166  * This handles the allocation and freeing of temporary flag
167  * layers and starting/stopping the modeling loop.
168  * Can be called from other operators exec callbacks as well.
169  */
170 void BMO_op_exec(BMesh *bm, BMOperator *op)
171 {
172         
173         BMO_push(bm, op);
174
175         if (bm->stackdepth == 2)
176                 bmesh_edit_begin(bm, op->flag);
177         op->exec(bm, op);
178         
179         if (bm->stackdepth == 2)
180                 bmesh_edit_end(bm, op->flag);
181         
182         BMO_pop(bm);
183 }
184
185 /**
186  * \brief BMESH OPSTACK FINISH OP
187  *
188  * Does housekeeping chores related to finishing up an operator.
189  */
190 void BMO_op_finish(BMesh *bm, BMOperator *op)
191 {
192         BMOpSlot *slot;
193         int i;
194
195         for (i = 0; opdefines[op->type]->slottypes[i].type; i++) {
196                 slot = &op->slots[i];
197                 if (slot->slottype == BMO_OP_SLOT_MAPPING) {
198                         if (slot->data.ghash)
199                                 BLI_ghash_free(slot->data.ghash, NULL, NULL);
200                 }
201         }
202
203         BLI_memarena_free(op->arena);
204
205 #ifdef DEBUG
206         BM_ELEM_INDEX_VALIDATE(bm, "post bmo", opdefines[op->type]->name);
207 #else
208         (void)bm;
209 #endif
210 }
211
212 /**
213  * \brief BMESH OPSTACK HAS SLOT
214  *
215  * \return Success if the slot if found.
216  */
217 int BMO_slot_exists(BMOperator *op, const char *slotname)
218 {
219         int slotcode = bmo_name_to_slotcode(opdefines[op->type], slotname);
220         return (slotcode >= 0);
221 }
222
223 /**
224  * \brief BMESH OPSTACK GET SLOT
225  *
226  * Returns a pointer to the slot of type 'slotcode'
227  */
228 BMOpSlot *BMO_slot_get(BMOperator *op, const char *slotname)
229 {
230         int slotcode = bmo_name_to_slotcode_check(opdefines[op->type], slotname);
231
232         if (slotcode < 0) {
233                 return &BMOpEmptySlot;
234         }
235
236         return &(op->slots[slotcode]);
237 }
238
239 /**
240  * \brief BMESH OPSTACK COPY SLOT
241  *
242  * Copies data from one slot to another.
243  */
244 void BMO_slot_copy(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
245 {
246         BMOpSlot *source_slot = BMO_slot_get(source_op, src);
247         BMOpSlot *dest_slot = BMO_slot_get(dest_op, dst);
248
249         if (source_slot == dest_slot)
250                 return;
251
252         if (source_slot->slottype != dest_slot->slottype) {
253                 /* possibly assert here? */
254                 return;
255         }
256
257         if (dest_slot->slottype  == BMO_OP_SLOT_ELEMENT_BUF) {
258                 /* do buffer copy */
259                 dest_slot->data.buf = NULL;
260                 dest_slot->len = source_slot->len;
261                 if (dest_slot->len) {
262                         const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
263                         dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
264                         memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
265                 }
266         }
267         else if (dest_slot->slottype  == BMO_OP_SLOT_MAPPING) {
268                 GHashIterator it;
269                 BMOElemMapping *srcmap, *dstmap;
270
271                 /* sanity check */
272                 if (!source_slot->data.ghash) {
273                         return;
274                 }
275
276                 if (!dest_slot->data.ghash) {
277                         dest_slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh operator 2");
278                 }
279
280                 BLI_ghashIterator_init(&it, source_slot->data.ghash);
281                 for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
282                           BLI_ghashIterator_step(&it))
283                 {
284                         dstmap = BLI_memarena_alloc(dest_op->arena, sizeof(*dstmap) + srcmap->len);
285
286                         dstmap->element = srcmap->element;
287                         dstmap->len = srcmap->len;
288                         memcpy(dstmap + 1, srcmap + 1, srcmap->len);
289
290                         BLI_ghash_insert(dest_slot->data.ghash, dstmap->element, dstmap);
291                 }
292         }
293         else {
294                 dest_slot->data = source_slot->data;
295         }
296 }
297
298 /*
299  * BMESH OPSTACK SET XXX
300  *
301  * Sets the value of a slot depending on it's type
302  */
303
304 void BMO_slot_float_set(BMOperator *op, const char *slotname, const float f)
305 {
306         BMOpSlot *slot = BMO_slot_get(op, slotname);
307         BLI_assert(slot->slottype == BMO_OP_SLOT_FLT);
308         if (!(slot->slottype == BMO_OP_SLOT_FLT))
309                 return;
310
311         slot->data.f = f;
312 }
313
314 void BMO_slot_int_set(BMOperator *op, const char *slotname, const int i)
315 {
316         BMOpSlot *slot = BMO_slot_get(op, slotname);
317         BLI_assert(slot->slottype == BMO_OP_SLOT_INT);
318         if (!(slot->slottype == BMO_OP_SLOT_INT))
319                 return;
320
321         slot->data.i = i;
322 }
323
324 void BMO_slot_bool_set(BMOperator *op, const char *slotname, const int i)
325 {
326         BMOpSlot *slot = BMO_slot_get(op, slotname);
327         BLI_assert(slot->slottype == BMO_OP_SLOT_BOOL);
328         if (!(slot->slottype == BMO_OP_SLOT_BOOL))
329                 return;
330
331         slot->data.i = i;
332 }
333
334 /* only supports square mats */
335 void BMO_slot_mat_set(BMOperator *op, const char *slotname, const float *mat, int size)
336 {
337         BMOpSlot *slot = BMO_slot_get(op, slotname);
338         BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
339         if (!(slot->slottype == BMO_OP_SLOT_MAT))
340                 return;
341
342         slot->len = 4;
343         slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
344         
345         if (size == 4) {
346                 memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
347         }
348         else if (size == 3) {
349                 copy_m4_m3(slot->data.p, (float (*)[3])mat);
350         }
351         else {
352                 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
353
354                 memset(slot->data.p, 0, sizeof(float) * 4 * 4);
355         }
356 }
357
358 void BMO_slot_mat4_get(BMOperator *op, const char *slotname, float r_mat[4][4])
359 {
360         BMOpSlot *slot = BMO_slot_get(op, slotname);
361         BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
362         if (!(slot->slottype == BMO_OP_SLOT_MAT))
363                 return;
364
365         copy_m4_m4(r_mat, (float (*)[4])slot->data.p);
366 }
367
368 void BMO_slot_mat3_set(BMOperator *op, const char *slotname, float r_mat[3][3])
369 {
370         BMOpSlot *slot = BMO_slot_get(op, slotname);
371         BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
372         if (!(slot->slottype == BMO_OP_SLOT_MAT))
373                 return;
374
375         copy_m3_m4(r_mat, slot->data.p);
376 }
377
378 void BMO_slot_ptr_set(BMOperator *op, const char *slotname, void *p)
379 {
380         BMOpSlot *slot = BMO_slot_get(op, slotname);
381         BLI_assert(slot->slottype == BMO_OP_SLOT_PNT);
382         if (!(slot->slottype == BMO_OP_SLOT_PNT))
383                 return;
384
385         slot->data.p = p;
386 }
387
388 void BMO_slot_vec_set(BMOperator *op, const char *slotname, const float vec[3])
389 {
390         BMOpSlot *slot = BMO_slot_get(op, slotname);
391         BLI_assert(slot->slottype == BMO_OP_SLOT_VEC);
392         if (!(slot->slottype == BMO_OP_SLOT_VEC))
393                 return;
394
395         copy_v3_v3(slot->data.vec, vec);
396 }
397
398
399 float BMO_slot_float_get(BMOperator *op, const char *slotname)
400 {
401         BMOpSlot *slot = BMO_slot_get(op, slotname);
402         BLI_assert(slot->slottype == BMO_OP_SLOT_FLT);
403         if (!(slot->slottype == BMO_OP_SLOT_FLT))
404                 return 0.0f;
405
406         return slot->data.f;
407 }
408
409 int BMO_slot_int_get(BMOperator *op, const char *slotname)
410 {
411         BMOpSlot *slot = BMO_slot_get(op, slotname);
412         BLI_assert(slot->slottype == BMO_OP_SLOT_INT);
413         if (!(slot->slottype == BMO_OP_SLOT_INT))
414                 return 0;
415
416         return slot->data.i;
417 }
418
419 int BMO_slot_bool_get(BMOperator *op, const char *slotname)
420 {
421         BMOpSlot *slot = BMO_slot_get(op, slotname);
422         BLI_assert(slot->slottype == BMO_OP_SLOT_BOOL);
423         if (!(slot->slottype == BMO_OP_SLOT_BOOL))
424                 return 0;
425
426         return slot->data.i;
427 }
428
429
430 void *BMO_slot_ptr_get(BMOperator *op, const char *slotname)
431 {
432         BMOpSlot *slot = BMO_slot_get(op, slotname);
433         BLI_assert(slot->slottype == BMO_OP_SLOT_PNT);
434         if (!(slot->slottype == BMO_OP_SLOT_PNT))
435                 return NULL;
436
437         return slot->data.p;
438 }
439
440 void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3])
441 {
442         BMOpSlot *slot = BMO_slot_get(op, slotname);
443         BLI_assert(slot->slottype == BMO_OP_SLOT_VEC);
444         if (!(slot->slottype == BMO_OP_SLOT_VEC))
445                 return;
446
447         copy_v3_v3(r_vec, slot->data.vec);
448 }
449
450 /*
451  * BMO_COUNTFLAG
452  *
453  * Counts the number of elements of a certain type that have a
454  * specific flag enabled (or disabled if test_for_enabled is false).
455  *
456  */
457
458 static int bmo_mesh_flag_count(BMesh *bm, const char htype, const short oflag,
459                                int test_for_enabled)
460 {
461         const char iter_types[3] = {BM_VERTS_OF_MESH,
462                                     BM_EDGES_OF_MESH,
463                                     BM_FACES_OF_MESH};
464
465         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
466
467         BMIter iter;
468         int count = 0;
469         BMElemF *ele_f;
470         const char hflag_test = (test_for_enabled ? oflag : 0);
471         int i;
472
473         for (i = 0; i < 3; i++) {
474                 if (htype & flag_types[i]) {
475                         BM_ITER(ele_f, &iter, bm, iter_types[i], NULL) {
476                                 if (BMO_elem_flag_test(bm, ele_f, oflag) == hflag_test)
477                                         count++;
478                         }
479                 }
480         }
481
482         return count;
483 }
484
485
486 int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag)
487 {
488         return bmo_mesh_flag_count(bm, htype, oflag, TRUE);
489 }
490
491 int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag)
492 {
493         return bmo_mesh_flag_count(bm, htype, oflag, FALSE);
494 }
495
496 void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
497 {
498         const char iter_types[3] = {BM_VERTS_OF_MESH,
499                                     BM_EDGES_OF_MESH,
500                                     BM_FACES_OF_MESH};
501
502         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
503
504         BMIter iter;
505         BMElemF *ele;
506         int i;
507
508         for (i = 0; i < 3; i++) {
509                 if (htype & flag_types[i]) {
510                         BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
511                                 BMO_elem_flag_disable(bm, ele, oflag);
512                         }
513                 }
514         }
515 }
516
517 int BMO_slot_buffer_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
518 {
519         BMOpSlot *slot = BMO_slot_get(op, slotname);
520         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
521         
522         /* check if its actually a buffer */
523         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
524                 return 0;
525
526         return slot->len;
527 }
528
529 int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
530 {
531         BMOpSlot *slot = BMO_slot_get(op, slotname);
532         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
533         
534         /* check if its actually a buffer */
535         if (!(slot->slottype == BMO_OP_SLOT_MAPPING))
536                 return 0;
537
538         return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
539 }
540
541 /* inserts a key/value mapping into a mapping slot.  note that it copies the
542  * value, it doesn't store a reference to it. */
543
544 void BMO_slot_map_insert(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
545                          void *element, void *data, int len)
546 {
547         BMOElemMapping *mapping;
548         BMOpSlot *slot = BMO_slot_get(op, slotname);
549         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
550
551         mapping = (BMOElemMapping *) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
552
553         mapping->element = (BMHeader *) element;
554         mapping->len = len;
555         memcpy(mapping + 1, data, len);
556
557         if (!slot->data.ghash) {
558                 slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh slot map hash");
559         }
560
561         BLI_ghash_insert(slot->data.ghash, element, mapping);
562 }
563
564 #if 0
565 void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slotcode, int totadd)
566 {
567         BMOpSlot *slot = &op->slots[slotcode];
568         void *tmp;
569         ssize_t allocsize;
570         
571         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
572
573         /* check if its actually a buffer */
574         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
575                 return NULL;
576
577         if (slot->flag & BMOS_DYNAMIC_ARRAY) {
578                 if (slot->len >= slot->size) {
579                         slot->size = (slot->size + 1 + totadd) * 2;
580
581                         allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size;
582
583                         tmp = slot->data.buf;
584                         slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
585                         memcpy(slot->data.buf, tmp, allocsize);
586                         MEM_freeN(tmp);
587                 }
588
589                 slot->len += totadd;
590         }
591         else {
592                 slot->flag |= BMOS_DYNAMIC_ARRAY;
593                 slot->len += totadd;
594                 slot->size = slot->len + 2;
595
596                 allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len;
597
598                 tmp = slot->data.buf;
599                 slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
600                 memcpy(slot->data.buf, tmp, allocsize);
601         }
602
603         return slot->data.buf;
604 }
605 #endif
606
607 void BMO_slot_map_to_flag(BMesh *bm, BMOperator *op, const char *slotname,
608                           const char htype, const short oflag)
609 {
610         GHashIterator it;
611         BMOpSlot *slot = BMO_slot_get(op, slotname);
612         BMElemF *ele_f;
613
614         BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
615
616         /* sanity check */
617         if (!slot->data.ghash) return;
618
619         BLI_ghashIterator_init(&it, slot->data.ghash);
620         for ( ; (ele_f = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
621                 if (ele_f->head.htype & htype) {
622                         BMO_elem_flag_enable(bm, ele_f, oflag);
623                 }
624         }
625 }
626
627 static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slotname, int len)
628 {
629         BMOpSlot *slot = BMO_slot_get(op, slotname);
630         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
631
632         /* check if its actually a buffer */
633         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
634                 return NULL;
635         
636         slot->len = len;
637         if (len)
638                 slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slottype] * len);
639         return slot->data.buf;
640 }
641
642 /**
643  * \brief BMO_ALL_TO_SLOT
644  *
645  * Copies all elements of a certain type into an operator slot.
646  */
647 static void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
648 {
649         BMOpSlot *output = BMO_slot_get(op, slotname);
650         int totelement = 0, i = 0;
651         
652         if (htype & BM_VERT) totelement += bm->totvert;
653         if (htype & BM_EDGE) totelement += bm->totedge;
654         if (htype & BM_FACE) totelement += bm->totface;
655
656         if (totelement) {
657                 BMIter iter;
658                 BMHeader *ele;
659
660                 bmo_slot_buffer_alloc(op, slotname, totelement);
661
662                 /* TODO - collapse these loops into one */
663
664                 if (htype & BM_VERT) {
665                         BM_ITER(ele, &iter, bm, BM_VERTS_OF_MESH, NULL) {
666                                 ((BMHeader **)output->data.p)[i] = ele;
667                                 i++;
668                         }
669                 }
670
671                 if (htype & BM_EDGE) {
672                         BM_ITER(ele, &iter, bm, BM_EDGES_OF_MESH, NULL) {
673                                 ((BMHeader **)output->data.p)[i] = ele;
674                                 i++;
675                         }
676                 }
677
678                 if (htype & BM_FACE) {
679                         BM_ITER(ele, &iter, bm, BM_FACES_OF_MESH, NULL) {
680                                 ((BMHeader **)output->data.p)[i] = ele;
681                                 i++;
682                         }
683                 }
684         }
685 }
686
687 /**
688  * \brief BMO_HEADERFLAG_TO_SLOT
689  *
690  * Copies elements of a certain type, which have a certain header flag
691  * enabled/disabled into a slot for an operator.
692  */
693 static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, const char *slotname,
694                                        const char htype, const char hflag,
695                                        int test_for_enabled)
696 {
697         BMOpSlot *output = BMO_slot_get(op, slotname);
698         int totelement = 0, i = 0;
699
700         if (test_for_enabled)
701                 totelement = BM_mesh_enabled_flag_count(bm, htype, hflag, TRUE);
702         else
703                 totelement = BM_mesh_disabled_flag_count(bm, htype, hflag, TRUE);
704
705         if (totelement) {
706                 BMIter iter;
707                 BMElem *ele;
708
709                 const char hflag_test = (test_for_enabled ? hflag : 0);
710
711                 bmo_slot_buffer_alloc(op, slotname, totelement);
712
713                 /* TODO - collapse these loops into one */
714
715                 if (htype & BM_VERT) {
716                         BM_ITER(ele, &iter, bm, BM_VERTS_OF_MESH, NULL) {
717                                 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
718                                     BM_elem_flag_test(ele, hflag) == hflag_test)
719                                 {
720                                         ((BMElem **)output->data.p)[i] = ele;
721                                         i++;
722                                 }
723                         }
724                 }
725
726                 if (htype & BM_EDGE) {
727                         BM_ITER(ele, &iter, bm, BM_EDGES_OF_MESH, NULL) {
728                                 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
729                                     BM_elem_flag_test(ele, hflag) == hflag_test)
730                                 {
731                                         ((BMElem **)output->data.p)[i] = ele;
732                                         i++;
733                                 }
734                         }
735                 }
736
737                 if (htype & BM_FACE) {
738                         BM_ITER(ele, &iter, bm, BM_FACES_OF_MESH, NULL) {
739                                 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
740                                     BM_elem_flag_test(ele, hflag) == hflag_test)
741                                 {
742                                         ((BMElem **)output->data.p)[i] = ele;
743                                         i++;
744                                 }
745                         }
746                 }
747         }
748         else {
749                 output->len = 0;
750         }
751 }
752
753 void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op, const char *slotname,
754                                         const char htype, const char hflag)
755 {
756         bmo_slot_buffer_from_hflag(bm, op, slotname, htype, hflag, TRUE);
757 }
758
759 void BMO_slot_buffer_from_disabled_hflag(BMesh *bm, BMOperator *op, const char *slotname,
760                                          const char htype, const char hflag)
761 {
762         bmo_slot_buffer_from_hflag(bm, op, slotname, htype, hflag, FALSE);
763 }
764
765 /**
766  * Copies the values from another slot to the end of the output slot.
767  */
768 void BMO_slot_buffer_append(BMOperator *output_op, const char *output_slot_name,
769                             BMOperator *other_op, const char *other_slot_name)
770 {
771         BMOpSlot *output_slot = BMO_slot_get(output_op, output_slot_name);
772         BMOpSlot *other_slot = BMO_slot_get(other_op, other_slot_name);
773
774         BLI_assert(output_slot->slottype == BMO_OP_SLOT_ELEMENT_BUF &&
775                    other_slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
776
777         if (output_slot->len == 0) {
778                 /* output slot is empty, copy rather than append */
779                 BMO_slot_copy(other_op, output_op, other_slot_name, output_slot_name);
780         }
781         else if (other_slot->len != 0) {
782                 int elem_size = BMO_OPSLOT_TYPEINFO[output_slot->slottype];
783                 int alloc_size = elem_size * (output_slot->len + other_slot->len);
784                 /* allocate new buffer */
785                 void *buf = BLI_memarena_alloc(output_op->arena, alloc_size);
786
787                 /* copy slot data */
788                 memcpy(buf, output_slot->data.buf, elem_size * output_slot->len);
789                 memcpy(((char*)buf) + elem_size * output_slot->len,
790                            other_slot->data.buf, elem_size * other_slot->len);
791
792                 output_slot->data.buf = buf;
793                 output_slot->len += other_slot->len;
794         }
795 }
796
797 /**
798  * \brief BMO_FLAG_TO_SLOT
799  *
800  * Copies elements of a certain type, which have a certain flag set
801  * into an output slot for an operator.
802  */
803 static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op, const char *slotname,
804                                       const char htype, const short oflag,
805                                       int test_for_enabled)
806 {
807         BMOpSlot *slot = BMO_slot_get(op, slotname);
808         int totelement, i = 0;
809
810         if (test_for_enabled)
811                 totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag);
812         else
813                 totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag);
814
815         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
816
817         if (totelement) {
818                 BMIter iter;
819                 BMHeader *ele;
820                 BMHeader **ele_array;
821                 const char hflag_test = (test_for_enabled ? oflag : 0);
822
823                 bmo_slot_buffer_alloc(op, slotname, totelement);
824
825                 ele_array = (BMHeader **)slot->data.p;
826
827                 /* TODO - collapse these loops into one */
828
829                 if (htype & BM_VERT) {
830                         BM_ITER(ele, &iter, bm, BM_VERTS_OF_MESH, NULL) {
831                                 if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag) == hflag_test) {
832                                         ele_array[i] = ele;
833                                         i++;
834                                 }
835                         }
836                 }
837
838                 if (htype & BM_EDGE) {
839                         BM_ITER(ele, &iter, bm, BM_EDGES_OF_MESH, NULL) {
840                                 if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag) == hflag_test) {
841                                         ele_array[i] = ele;
842                                         i++;
843                                 }
844                         }
845                 }
846
847                 if (htype & BM_FACE) {
848                         BM_ITER(ele, &iter, bm, BM_FACES_OF_MESH, NULL) {
849                                 if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag) == hflag_test) {
850                                         ele_array[i] = ele;
851                                         i++;
852                                 }
853                         }
854                 }
855         }
856         else {
857                 slot->len = 0;
858         }
859 }
860
861 void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, const char *slotname,
862                                        const char htype, const short oflag)
863 {
864         bmo_slot_buffer_from_flag(bm, op, slotname, htype, oflag, TRUE);
865 }
866
867 void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op, const char *slotname,
868                                         const char htype, const short oflag)
869 {
870         bmo_slot_buffer_from_flag(bm, op, slotname, htype, oflag, FALSE);
871 }
872
873 /**
874  * \brief BMO_FLAG_BUFFER
875  *
876  * Header Flags elements in a slots buffer, automatically
877  * using the selection API where appropriate.
878  */
879 void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slotname,
880                                   const char htype, const char hflag, const char do_flush)
881 {
882         BMOpSlot *slot = BMO_slot_get(op, slotname);
883         BMElem **data =  slot->data.p;
884         int i;
885         const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
886         const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
887
888         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
889
890         for (i = 0; i < slot->len; i++, data++) {
891                 if (!(htype & (*data)->head.htype))
892                         continue;
893
894                 if (do_flush_select) {
895                         BM_elem_select_set(bm, *data, TRUE);
896                 }
897
898                 if (do_flush_hide) {
899                         BM_elem_hide_set(bm, *data, FALSE);
900                 }
901
902                 BM_elem_flag_enable(*data, hflag);
903         }
904 }
905
906 /**
907  * \brief BMO_FLAG_BUFFER
908  *
909  * Removes flags from elements in a slots buffer, automatically
910  * using the selection API where appropriate.
911  */
912 void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slotname,
913                                    const char htype, const char hflag, const char do_flush)
914 {
915         BMOpSlot *slot = BMO_slot_get(op, slotname);
916         BMElem **data =  slot->data.p;
917         int i;
918         const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
919         const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
920
921         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
922
923         for (i = 0; i < slot->len; i++, data++) {
924                 if (!(htype & (*data)->head.htype))
925                         continue;
926
927                 if (do_flush_select) {
928                         BM_elem_select_set(bm, *data, FALSE);
929                 }
930
931                 if (do_flush_hide) {
932                         BM_elem_hide_set(bm, *data, FALSE);
933                 }
934
935                 BM_elem_flag_disable(*data, hflag);
936         }
937 }
938
939 int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
940 {
941         int count = 0;
942
943         if (v->e) {
944                 BMEdge *curedge;
945                 const int len = bmesh_disk_count(v);
946                 int i;
947                 
948                 for (i = 0, curedge = v->e; i < len; i++) {
949                         if (BMO_elem_flag_test(bm, curedge, oflag))
950                                 count++;
951                         curedge = bmesh_disk_edge_next(curedge, v);
952                 }
953         }
954
955         return count;
956 }
957
958 /**
959  * \brief BMO_FLAG_BUFFER
960  *
961  * Flags elements in a slots buffer
962  */
963 void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slotname,
964                                  const char htype, const short oflag)
965 {
966         BMOpSlot *slot = BMO_slot_get(op, slotname);
967         BMHeader **data =  slot->data.p;
968         int i;
969
970         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
971
972         for (i = 0; i < slot->len; i++) {
973                 if (!(htype & data[i]->htype))
974                         continue;
975
976                 BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
977         }
978 }
979
980 /**
981  * \brief BMO_FLAG_BUFFER
982  *
983  * Removes flags from elements in a slots buffer
984  */
985 void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slotname,
986                                   const char htype, const short oflag)
987 {
988         BMOpSlot *slot = BMO_slot_get(op, slotname);
989         BMHeader **data =  slot->data.p;
990         int i;
991
992         BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
993
994         for (i = 0; i < slot->len; i++) {
995                 if (!(htype & data[i]->htype))
996                         continue;
997
998                 BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
999         }
1000 }
1001
1002
1003 /**
1004  * \brief ALLOC/FREE FLAG LAYER
1005  *
1006  * Used by operator stack to free/allocate
1007  * private flag data. This is allocated
1008  * using a mempool so the allocation/frees
1009  * should be quite fast.
1010  *
1011  * BMESH_TODO:
1012  * Investigate not freeing flag layers until
1013  * all operators have been executed. This would
1014  * save a lot of realloc potentially.
1015  */
1016 static void bmo_flag_layer_alloc(BMesh *bm)
1017 {
1018         BMElemF *ele;
1019         /* set the index values since we are looping over all data anyway,
1020          * may save time later on */
1021         int i;
1022
1023         BMIter iter;
1024         BLI_mempool *oldpool = bm->toolflagpool;                /* old flag pool */
1025         BLI_mempool *newpool;
1026         void *oldflags;
1027
1028         /* store memcpy size for reuse */
1029         const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
1030         
1031         bm->totflags++;
1032
1033         /* allocate new flag poo */
1034         bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, 512, 512, 0);
1035         
1036         /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
1037         BM_ITER_INDEX(ele, &iter, bm, BM_VERTS_OF_MESH, NULL, i) {
1038                 oldflags = ele->oflags;
1039                 ele->oflags = BLI_mempool_calloc(newpool);
1040                 memcpy(ele->oflags, oldflags, old_totflags_size);
1041                 BM_elem_index_set(ele, i); /* set_inline */
1042         }
1043         BM_ITER_INDEX(ele, &iter, bm, BM_EDGES_OF_MESH, NULL, i) {
1044                 oldflags = ele->oflags;
1045                 ele->oflags = BLI_mempool_calloc(newpool);
1046                 memcpy(ele->oflags, oldflags, old_totflags_size);
1047                 BM_elem_index_set(ele, i); /* set_inline */
1048         }
1049         BM_ITER_INDEX(ele, &iter, bm, BM_FACES_OF_MESH, NULL, i) {
1050                 oldflags = ele->oflags;
1051                 ele->oflags = BLI_mempool_calloc(newpool);
1052                 memcpy(ele->oflags, oldflags, old_totflags_size);
1053                 BM_elem_index_set(ele, i); /* set_inline */
1054         }
1055
1056         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1057
1058         BLI_mempool_destroy(oldpool);
1059 }
1060
1061 static void bmo_flag_layer_free(BMesh *bm)
1062 {
1063         BMElemF *ele;
1064         /* set the index values since we are looping over all data anyway,
1065          * may save time later on */
1066         int i;
1067
1068         BMIter iter;
1069         BLI_mempool *oldpool = bm->toolflagpool;
1070         BLI_mempool *newpool;
1071         void *oldflags;
1072         
1073         /* store memcpy size for reuse */
1074         const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
1075
1076         /* de-increment the totflags first.. */
1077         bm->totflags--;
1078         /* allocate new flag poo */
1079         bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, BLI_MEMPOOL_SYSMALLOC);
1080         
1081         /* now go through and memcpy all the flag */
1082         BM_ITER_INDEX(ele, &iter, bm, BM_VERTS_OF_MESH, NULL, i) {
1083                 oldflags = ele->oflags;
1084                 ele->oflags = BLI_mempool_calloc(newpool);
1085                 memcpy(ele->oflags, oldflags, new_totflags_size);
1086                 BM_elem_index_set(ele, i); /* set_inline */
1087         }
1088         BM_ITER_INDEX(ele, &iter, bm, BM_EDGES_OF_MESH, NULL, i) {
1089                 oldflags = ele->oflags;
1090                 ele->oflags = BLI_mempool_calloc(newpool);
1091                 memcpy(ele->oflags, oldflags, new_totflags_size);
1092                 BM_elem_index_set(ele, i); /* set_inline */
1093         }
1094         BM_ITER_INDEX(ele, &iter, bm, BM_FACES_OF_MESH, NULL, i) {
1095                 oldflags = ele->oflags;
1096                 ele->oflags = BLI_mempool_calloc(newpool);
1097                 memcpy(ele->oflags, oldflags, new_totflags_size);
1098                 BM_elem_index_set(ele, i); /* set_inline */
1099         }
1100
1101         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1102
1103         BLI_mempool_destroy(oldpool);
1104 }
1105
1106 static void bmo_flag_layer_clear(BMesh *bm)
1107 {
1108         BMElemF *ele;
1109         /* set the index values since we are looping over all data anyway,
1110          * may save time later on */
1111         int i;
1112
1113         BMIter iter;
1114         const int totflags_offset = bm->totflags - 1;
1115
1116         /* now go through and memcpy all the flag */
1117         BM_ITER_INDEX(ele, &iter, bm, BM_VERTS_OF_MESH, NULL, i) {
1118                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1119                 BM_elem_index_set(ele, i); /* set_inline */
1120         }
1121         BM_ITER_INDEX(ele, &iter, bm, BM_EDGES_OF_MESH, NULL, i) {
1122                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1123                 BM_elem_index_set(ele, i); /* set_inline */
1124         }
1125         BM_ITER_INDEX(ele, &iter, bm, BM_FACES_OF_MESH, NULL, i) {
1126                 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1127                 BM_elem_index_set(ele, i); /* set_inline */
1128         }
1129
1130         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1131 }
1132
1133 void *BMO_slot_buffer_elem_first(BMOperator *op, const char *slotname)
1134 {
1135         BMOpSlot *slot = BMO_slot_get(op, slotname);
1136         
1137         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
1138                 return NULL;
1139
1140         return slot->data.buf ? *(void **)slot->data.buf : NULL;
1141 }
1142
1143 /**
1144  * \brief New Iterator
1145  *
1146  * \param restrictmask restricts the iteration to certain element types
1147  * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
1148  * over an element buffer (not a mapping). */
1149 void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
1150                    const char *slotname, const char restrictmask)
1151 {
1152         BMOpSlot *slot = BMO_slot_get(op, slotname);
1153
1154         memset(iter, 0, sizeof(BMOIter));
1155
1156         iter->slot = slot;
1157         iter->cur = 0;
1158         iter->restrictmask = restrictmask;
1159
1160         if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1161                 if (iter->slot->data.ghash) {
1162                         BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1163                 }
1164                 else {
1165                         return NULL;
1166                 }
1167         }
1168
1169         return BMO_iter_step(iter);
1170 }
1171
1172 void *BMO_iter_step(BMOIter *iter)
1173 {
1174         if (iter->slot->slottype == BMO_OP_SLOT_ELEMENT_BUF) {
1175                 BMHeader *h;
1176
1177                 if (iter->cur >= iter->slot->len) {
1178                         return NULL;
1179                 }
1180
1181                 h = ((void **)iter->slot->data.buf)[iter->cur++];
1182                 while (!(iter->restrictmask & h->htype)) {
1183                         if (iter->cur >= iter->slot->len) {
1184                                 return NULL;
1185                         }
1186
1187                         h = ((void **)iter->slot->data.buf)[iter->cur++];
1188                 }
1189
1190                 return h;
1191         }
1192         else if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1193                 BMOElemMapping *map;
1194                 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1195                 map = BLI_ghashIterator_getValue(&iter->giter);
1196                 
1197                 iter->val = map + 1;
1198
1199                 BLI_ghashIterator_step(&iter->giter);
1200
1201                 return ret;
1202         }
1203
1204         return NULL;
1205 }
1206
1207 /* used for iterating over mapping */
1208 void *BMO_iter_map_value(BMOIter *iter)
1209 {
1210         return iter->val;
1211 }
1212
1213 void *BMO_iter_map_value_p(BMOIter *iter)
1214 {
1215         return *((void **)iter->val);
1216 }
1217
1218 float BMO_iter_map_value_f(BMOIter *iter)
1219 {
1220         return *((float *)iter->val);
1221 }
1222
1223 /* error syste */
1224 typedef struct BMOpError {
1225         struct BMOpError *next, *prev;
1226         int errorcode;
1227         BMOperator *op;
1228         const char *msg;
1229 } BMOpError;
1230
1231 void BMO_error_clear(BMesh *bm)
1232 {
1233         while (BMO_error_pop(bm, NULL, NULL));
1234 }
1235
1236 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1237 {
1238         BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1239         
1240         err->errorcode = errcode;
1241         if (!msg) msg = bmo_error_messages[errcode];
1242         err->msg = msg;
1243         err->op = owner;
1244         
1245         BLI_addhead(&bm->errorstack, err);
1246 }
1247
1248 int BMO_error_occurred(BMesh *bm)
1249 {
1250         return bm->errorstack.first != NULL;
1251 }
1252
1253 /* returns error code or 0 if no erro */
1254 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1255 {
1256         BMOpError *err = bm->errorstack.first;
1257         if (!err) {
1258                 return 0;
1259         }
1260
1261         if (msg) *msg = err->msg;
1262         if (op) *op = err->op;
1263         
1264         return err->errorcode;
1265 }
1266
1267 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1268 {
1269         int errorcode = BMO_error_get(bm, msg, op);
1270         
1271         if (errorcode) {
1272                 BMOpError *err = bm->errorstack.first;
1273                 
1274                 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1275                 MEM_freeN(err);
1276         }
1277
1278         return errorcode;
1279 }
1280
1281
1282 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1283
1284 static int bmo_name_to_slotcode(BMOpDefine *def, const char *name)
1285 {
1286         int i;
1287
1288         for (i = 0; def->slottypes[i].type; i++) {
1289                 if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
1290                         return i;
1291                 }
1292         }
1293
1294         return -1;
1295 }
1296
1297 static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name)
1298 {
1299         int i = bmo_name_to_slotcode(def, name);
1300         if (i < 0) {
1301                 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1302         }
1303
1304         return i;
1305 }
1306
1307 static int bmo_opname_to_opcode(const char *opname)
1308 {
1309         int i;
1310
1311         for (i = 0; i < bmesh_total_ops; i++) {
1312                 if (!strcmp(opname, opdefines[i]->name)) {
1313                         return i;
1314                 }
1315         }
1316
1317         fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1318         return -1;
1319 }
1320
1321 /* Example:
1322  * BMO_op_callf(bm, "del %i %hv", DEL_ONLYFACES, BM_ELEM_SELECT);
1323  *
1324  *  i - int
1325  *  b - boolean (same as int but 1/0 only)
1326  *  f - float
1327  *  hv - header flagged verts (hflag)
1328  *  he - header flagged edges (hflag)
1329  *  hf - header flagged faces (hflag)
1330  *  fv - flagged verts (oflag)
1331  *  fe - flagged edges (oflag)
1332  *  ff - flagged faces (oflag)
1333  */
1334
1335 int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1336 {
1337         BMOpDefine *def;
1338         char *opname, *ofmt, *fmt;
1339         char slotname[64] = {0};
1340         int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, type, state;
1341         char htype;
1342         int noslot = 0;
1343
1344
1345         /* basic useful info to help find where bmop formatting strings fail */
1346         const char *err_reason = "Unknown";
1347         int lineno = -1;
1348
1349 #define GOTO_ERROR(reason)   \
1350         {                        \
1351                 err_reason = reason; \
1352                 lineno = __LINE__;   \
1353                 goto error;          \
1354         } (void)0
1355
1356         /* we muck around in here, so dup i */
1357         fmt = ofmt = BLI_strdup(_fmt);
1358         
1359         /* find operator name */
1360         i = strcspn(fmt, " ");
1361
1362         opname = fmt;
1363         if (!opname[i]) noslot = 1;
1364         opname[i] = '\0';
1365
1366         fmt += i + (noslot ? 0 : 1);
1367         
1368         i = bmo_opname_to_opcode(opname);
1369
1370         if (i == -1) {
1371                 MEM_freeN(ofmt);
1372                 return FALSE;
1373         }
1374
1375         BMO_op_init(bm, op, opname);
1376         def = opdefines[i];
1377         
1378         i = 0;
1379         state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1380
1381         while (*fmt) {
1382                 if (state) {
1383                         /* jump past leading whitespac */
1384                         i = strspn(fmt, " ");
1385                         fmt += i;
1386                         
1387                         /* ignore trailing whitespac */
1388                         if (!fmt[i])
1389                                 break;
1390
1391                         /* find end of slot name, only "slot=%f", can be used */
1392                         i = strcspn(fmt, "=");
1393                         if (!fmt[i]) {
1394                                 GOTO_ERROR("could not match end of slot name");
1395                         }
1396
1397                         fmt[i] = 0;
1398
1399                         if (bmo_name_to_slotcode_check(def, fmt) < 0) {
1400                                 GOTO_ERROR("name to slot code check failed");
1401                         }
1402                         
1403                         BLI_strncpy(slotname, fmt, sizeof(slotname));
1404                         
1405                         state = 0;
1406                         fmt += i;
1407                 }
1408                 else {
1409                         switch (*fmt) {
1410                                 case ' ':
1411                                 case '=':
1412                                 case '%':
1413                                         break;
1414                                 case 'm': {
1415                                         int size, c;
1416
1417                                         c = NEXT_CHAR(fmt);
1418                                         fmt++;
1419
1420                                         if      (c == '3') size = 3;
1421                                         else if (c == '4') size = 4;
1422                                         else GOTO_ERROR("matrix size was not 3 or 4");
1423
1424                                         BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
1425                                         state = 1;
1426                                         break;
1427                                 }
1428                                 case 'v': {
1429                                         BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
1430                                         state = 1;
1431                                         break;
1432                                 }
1433                                 case 'e': {
1434                                         BMHeader *ele = va_arg(vlist, void *);
1435                                         BMOpSlot *slot = BMO_slot_get(op, slotname);
1436
1437                                         slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1438                                         slot->len = 1;
1439                                         *((void **)slot->data.buf) = ele;
1440
1441                                         state = 1;
1442                                         break;
1443                                 }
1444                                 case 's': {
1445                                         BMOperator *op2 = va_arg(vlist, void *);
1446                                         const char *slotname2 = va_arg(vlist, char *);
1447
1448                                         BMO_slot_copy(op2, op, slotname2, slotname);
1449                                         state = 1;
1450                                         break;
1451                                 }
1452                                 case 'i':
1453                                         BMO_slot_int_set(op, slotname, va_arg(vlist, int));
1454                                         state = 1;
1455                                         break;
1456                                 case 'b':
1457                                         BMO_slot_bool_set(op, slotname, va_arg(vlist, int));
1458                                         state = 1;
1459                                         break;
1460                                 case 'p':
1461                                         BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
1462                                         state = 1;
1463                                         break;
1464                                 case 'f':
1465                                 case 'F':
1466                                 case 'h':
1467                                 case 'H':
1468                                 case 'a':
1469                                         type = *fmt;
1470
1471                                         if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\0') {
1472                                                 BMO_slot_float_set(op, slotname, va_arg(vlist, double));
1473                                         }
1474                                         else {
1475                                                 htype = 0;
1476                                                 stop = 0;
1477                                                 while (1) {
1478                                                         switch (NEXT_CHAR(fmt)) {
1479                                                                 case 'f': htype |= BM_FACE; break;
1480                                                                 case 'e': htype |= BM_EDGE; break;
1481                                                                 case 'v': htype |= BM_VERT; break;
1482                                                                 default:
1483                                                                         stop = 1;
1484                                                                         break;
1485                                                         }
1486                                                         if (stop) {
1487                                                                 break;
1488                                                         }
1489
1490                                                         fmt++;
1491                                                 }
1492
1493                                                 if (type == 'h') {
1494                                                         BMO_slot_buffer_from_enabled_hflag(bm, op, slotname, htype, va_arg(vlist, int));
1495                                                 }
1496                                                 else if (type == 'H') {
1497                                                         BMO_slot_buffer_from_disabled_hflag(bm, op, slotname, htype, va_arg(vlist, int));
1498                                                 }
1499                                                 else if (type == 'a') {
1500                                                         BMO_slot_buffer_from_all(bm, op, slotname, htype);
1501                                                 }
1502                                                 else if (type == 'f') {
1503                                                         BMO_slot_buffer_from_enabled_flag(bm, op, slotname, htype, va_arg(vlist, int));
1504                                                 }
1505                                                 else if (type == 'F') {
1506                                                         BMO_slot_buffer_from_disabled_flag(bm, op, slotname, htype, va_arg(vlist, int));
1507                                                 }
1508                                         }
1509
1510                                         state = 1;
1511                                         break;
1512                                 default:
1513                                         fprintf(stderr,
1514                                                 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1515                                                 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1516                                         break;
1517                         }
1518                 }
1519                 fmt++;
1520         }
1521
1522         MEM_freeN(ofmt);
1523         return TRUE;
1524 error:
1525
1526         /* non urgent todo - explain exactly what is failing */
1527         fprintf(stderr, "%s: error parsing formatting string\n", __func__);
1528
1529         fprintf(stderr, "string: '%s', position %d\n", _fmt, (int)(fmt - ofmt));
1530         fprintf(stderr, "         ");
1531         {
1532                 int pos = (int)(fmt - ofmt);
1533                 int i;
1534                 for (i = 0; i < pos; i++) {
1535                         fprintf(stderr, " ");
1536                 }
1537                 fprintf(stderr, "^\n");
1538         }
1539
1540         fprintf(stderr, "source code:  %s:%d\n", __FILE__, lineno);
1541
1542         fprintf(stderr, "reason: %s\n", err_reason);
1543
1544
1545         MEM_freeN(ofmt);
1546
1547         BMO_op_finish(bm, op);
1548         return FALSE;
1549
1550 #undef GOTO_ERROR
1551
1552 }
1553
1554
1555 int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1556 {
1557         va_list list;
1558
1559         va_start(list, fmt);
1560         if (!BMO_op_vinitf(bm, op, fmt, list)) {
1561                 printf("%s: failed\n", __func__);
1562                 va_end(list);
1563                 return FALSE;
1564         }
1565         va_end(list);
1566
1567         return TRUE;
1568 }
1569
1570 int BMO_op_callf(BMesh *bm, const char *fmt, ...)
1571 {
1572         va_list list;
1573         BMOperator op;
1574
1575         va_start(list, fmt);
1576         if (!BMO_op_vinitf(bm, &op, fmt, list)) {
1577                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1578                 va_end(list);
1579                 return FALSE;
1580         }
1581
1582         BMO_op_exec(bm, &op);
1583         BMO_op_finish(bm, &op);
1584
1585         va_end(list);
1586         return TRUE;
1587 }