style cleanup > 120 line length.
[blender-staging.git] / source / blender / bmesh / intern / bmesh_operators.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/intern/bmesh_operators.c
24  *  \ingroup bmesh
25  *
26  * BMesh operator access.
27  */
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_utildefines.h"
32 #include "BLI_string.h"
33 #include "BLI_math.h"
34 #include "BLI_memarena.h"
35 #include "BLI_mempool.h"
36 #include "BLI_listbase.h"
37 #include "BLI_array.h"
38
39 #include "bmesh.h"
40 #include "bmesh_private.h"
41
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 bmesh_name_to_slotcode(BMOpDefine *def, const char *name);
47 static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name);
48 static int bmesh_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         "Tesselation 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[] = {
67         0,
68         sizeof(int),
69         sizeof(float),
70         sizeof(void *),
71         0, /* unused */
72         0, /* unused */
73         0, /* unused */
74         sizeof(void *), /* pointer buffer */
75         sizeof(BMOElemMapping)
76 };
77
78 /* Dummy slot so there is something to return when slot name lookup fails */
79 static BMOpSlot BMOpEmptySlot = {0};
80
81 void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
82 {
83         op->flag |= op_flag;
84 }
85
86 void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
87 {
88         op->flag &= ~op_flag;
89 }
90
91 /*
92  * BMESH OPSTACK PUSH
93  *
94  * Pushes the opstack down one level
95  * and allocates a new flag layer if
96  * 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  * BMESH OPSTACK POP
111  *
112  * Pops the opstack one level
113  * and frees a flag layer if appropriate
114  * BMESH_TODO: investigate NOT freeing flag
115  * layers.
116  */
117 void BMO_pop(BMesh *bm)
118 {
119         if (bm->stackdepth > 1)
120                 bmo_flag_layer_free(bm);
121
122         bm->stackdepth--;
123 }
124
125 /*
126  * BMESH OPSTACK INIT OP
127  *
128  * Initializes an operator structure
129  * to a certain type
130  */
131 void BMO_op_init(BMesh *bm, BMOperator *op, const char *opname)
132 {
133         int i, opcode = bmesh_opname_to_opcode(opname);
134
135 #ifdef DEBUG
136         BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
137 #else
138         (void)bm;
139 #endif
140
141         if (opcode == -1) {
142                 opcode = 0; /* error!, already printed, have a better way to handle this? */
143         }
144
145         memset(op, 0, sizeof(BMOperator));
146         op->type = opcode;
147         op->flag = opdefines[opcode]->flag;
148         
149         /* initialize the operator slot types */
150         for (i = 0; opdefines[opcode]->slottypes[i].type; i++) {
151                 op->slots[i].slottype = opdefines[opcode]->slottypes[i].type;
152                 op->slots[i].index = i;
153         }
154
155         /* callback */
156         op->exec = opdefines[opcode]->exec;
157
158         /* memarena, used for operator's slot buffers */
159         op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bmesh operator");
160         BLI_memarena_use_calloc (op->arena);
161 }
162
163 /*
164  * BMESH OPSTACK EXEC OP
165  *
166  * Executes a passed in operator. This handles
167  * the allocation and freeing of temporary flag
168  * layers and starting/stopping the modelling
169  * loop. Can be called from other operators
170  * exec callbacks as well.
171  */
172 void BMO_op_exec(BMesh *bm, BMOperator *op)
173 {
174         
175         BMO_push(bm, op);
176
177         if (bm->stackdepth == 2)
178                 bmesh_begin_edit(bm, op->flag);
179         op->exec(bm, op);
180         
181         if (bm->stackdepth == 2)
182                 bmesh_end_edit(bm, op->flag);
183         
184         BMO_pop(bm);
185 }
186
187 /*
188  * BMESH OPSTACK FINISH OP
189  *
190  * Does housekeeping chores related to finishing
191  * up an operator.
192  */
193 void BMO_op_finish(BMesh *bm, BMOperator *op)
194 {
195         BMOpSlot *slot;
196         int i;
197
198         for (i = 0; opdefines[op->type]->slottypes[i].type; i++) {
199                 slot = &op->slots[i];
200                 if (slot->slottype == BMO_OP_SLOT_MAPPING) {
201                         if (slot->data.ghash)
202                                 BLI_ghash_free(slot->data.ghash, NULL, NULL);
203                 }
204         }
205
206         BLI_memarena_free(op->arena);
207
208 #ifdef DEBUG
209         BM_ELEM_INDEX_VALIDATE(bm, "post bmo", opdefines[op->type]->name);
210 #else
211         (void)bm;
212 #endif
213 }
214
215 /*
216  * BMESH OPSTACK HAS SLOT
217  *
218  * Returns 1 if the named slot exists on the given operator,
219  * otherwise returns 0.
220  */
221 int BMO_slot_exists(BMOperator *op, const char *slotname)
222 {
223         int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname);
224         return (slotcode >= 0);
225 }
226
227 /*
228  * BMESH OPSTACK GET SLOT
229  *
230  * Returns a pointer to the slot of
231  * type 'slotcode'
232  */
233 BMOpSlot *BMO_slot_get(BMOperator *op, const char *slotname)
234 {
235         int slotcode = bmesh_name_to_slotcode_check(opdefines[op->type], slotname);
236
237         if (slotcode < 0) {
238                 return &BMOpEmptySlot;
239         }
240
241         return &(op->slots[slotcode]);
242 }
243
244 /*
245  * BMESH OPSTACK COPY SLOT
246  *
247  * Copies data from one slot to another
248  */
249 void BMO_slot_copy(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
250 {
251         BMOpSlot *source_slot = BMO_slot_get(source_op, src);
252         BMOpSlot *dest_slot = BMO_slot_get(dest_op, dst);
253
254         if (source_slot == dest_slot)
255                 return;
256
257         if (source_slot->slottype != dest_slot->slottype)
258                 return;
259         
260         if (dest_slot->slottype > BMO_OP_SLOT_VEC) {
261                 if (dest_slot->slottype != BMO_OP_SLOT_MAPPING) {
262                         /* do buffer copy */
263                         dest_slot->data.buf = NULL;
264                         dest_slot->len = source_slot->len;
265                         if (dest_slot->len) {
266                                 const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
267                                 dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
268                                 memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
269                         }
270                 }
271                 else {
272                         GHashIterator it;
273                         BMOElemMapping *srcmap, *dstmap;
274
275                         /* sanity check */
276                         if (!source_slot->data.ghash) return;
277                         
278                         if (!dest_slot->data.ghash) {
279                                 dest_slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
280                                                                       BLI_ghashutil_ptrcmp, "bmesh operator 2");
281                         }
282
283                         BLI_ghashIterator_init(&it, source_slot->data.ghash);
284                         for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
285                               BLI_ghashIterator_step(&it))
286                         {
287                                 dstmap = BLI_memarena_alloc(dest_op->arena, sizeof(*dstmap) + srcmap->len);
288
289                                 dstmap->element = srcmap->element;
290                                 dstmap->len = srcmap->len;
291                                 memcpy(dstmap + 1, srcmap + 1, srcmap->len);
292
293                                 BLI_ghash_insert(dest_slot->data.ghash, dstmap->element, dstmap);
294                         }
295                 }
296         }
297         else {
298                 dest_slot->data = source_slot->data;
299         }
300 }
301
302 /*
303  * BMESH OPSTACK SET XXX
304  *
305  * Sets the value of a slot depending on it's type
306  *
307  */
308
309 void BMO_slot_float_set(BMOperator *op, const char *slotname, float f)
310 {
311         BMOpSlot *slot = BMO_slot_get(op, slotname);
312         if (!(slot->slottype == BMO_OP_SLOT_FLT))
313                 return;
314
315         slot->data.f = f;
316 }
317
318 void BMO_slot_int_set(BMOperator *op, const char *slotname, int i)
319 {
320         BMOpSlot *slot = BMO_slot_get(op, slotname);
321         if (!(slot->slottype == BMO_OP_SLOT_INT))
322                 return;
323
324         slot->data.i = i;
325 }
326
327 /* only supports square mats */
328 void BMO_slot_mat_set(struct BMOperator *op, const char *slotname, float *mat, int size)
329 {
330         BMOpSlot *slot = BMO_slot_get(op, slotname);
331         if (!(slot->slottype == BMO_OP_SLOT_MAT))
332                 return;
333
334         slot->len = 4;
335         slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
336         
337         if (size == 4) {
338                 memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
339         }
340         else if (size == 3) {
341                 copy_m4_m3(slot->data.p, (float (*)[3])mat);
342         }
343         else {
344                 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
345
346                 memset(slot->data.p, 0, sizeof(float) * 4 * 4);
347                 return;
348         }
349 }
350
351 void BMO_slot_mat4_set(struct BMOperator *op, const char *slotname, float mat[4][4])
352 {
353         BMOpSlot *slot = BMO_slot_get(op, slotname);
354         if (!(slot->slottype == BMO_OP_SLOT_MAT))
355                 return;
356
357         memcpy(mat, slot->data.p, sizeof(float) * 4 * 4);
358 }
359
360 void BMO_slot_mat3_set(struct BMOperator *op, const char *slotname, float mat[3][3])
361 {
362         BMOpSlot *slot = BMO_slot_get(op, slotname);
363         if (!(slot->slottype == BMO_OP_SLOT_MAT))
364                 return;
365
366         copy_m3_m4(mat, slot->data.p);
367 }
368
369 void BMO_slot_ptr_set(BMOperator *op, const char *slotname, void *p)
370 {
371         BMOpSlot *slot = BMO_slot_get(op, slotname);
372         if (!(slot->slottype == BMO_OP_SLOT_PNT))
373                 return;
374
375         slot->data.p = p;
376 }
377
378 void BMO_slot_vec_set(BMOperator *op, const char *slotname, const float vec[3])
379 {
380         BMOpSlot *slot = BMO_slot_get(op, slotname);
381         if (!(slot->slottype == BMO_OP_SLOT_VEC))
382                 return;
383
384         copy_v3_v3(slot->data.vec, vec);
385 }
386
387
388 float BMO_slot_float_get(BMOperator *op, const char *slotname)
389 {
390         BMOpSlot *slot = BMO_slot_get(op, slotname);
391         if (!(slot->slottype == BMO_OP_SLOT_FLT))
392                 return 0.0f;
393
394         return slot->data.f;
395 }
396
397 int BMO_slot_int_get(BMOperator *op, const char *slotname)
398 {
399         BMOpSlot *slot = BMO_slot_get(op, slotname);
400         if (!(slot->slottype == BMO_OP_SLOT_INT))
401                 return 0;
402
403         return slot->data.i;
404 }
405
406
407 void *BMO_slot_ptr_get(BMOperator *op, const char *slotname)
408 {
409         BMOpSlot *slot = BMO_slot_get(op, slotname);
410         if (!(slot->slottype == BMO_OP_SLOT_PNT))
411                 return NULL;
412
413         return slot->data.p;
414 }
415
416 void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3])
417 {
418         BMOpSlot *slot = BMO_slot_get(op, slotname);
419         if (!(slot->slottype == BMO_OP_SLOT_VEC))
420                 return;
421
422         copy_v3_v3(r_vec, slot->data.vec);
423 }
424
425 /*
426  * BMO_COUNTFLAG
427  *
428  * Counts the number of elements of a certain type that
429  * have a specific flag set.
430  *
431  */
432
433 int BMO_mesh_flag_count(BMesh *bm, const short oflag, const char htype)
434 {
435         BMIter elements;
436         BMHeader *e;
437         int count = 0;
438
439         if (htype & BM_VERT) {
440                 for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
441                         if (BMO_elem_flag_test(bm, e, oflag))
442                                 count++;
443                 }
444         }
445         if (htype & BM_EDGE) {
446                 for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
447                         if (BMO_elem_flag_test(bm, e, oflag))
448                                 count++;
449                 }
450         }
451         if (htype & BM_FACE) {
452                 for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
453                         if (BMO_elem_flag_test(bm, e, oflag))
454                                 count++;
455                 }
456         }
457
458         return count;
459 }
460
461 void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
462 {
463         const char iter_types[3] = {BM_VERTS_OF_MESH,
464                                     BM_EDGES_OF_MESH,
465                                     BM_FACES_OF_MESH};
466
467         const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
468
469         BMIter iter;
470         BMHeader *ele;
471         int i;
472
473         for (i = 0; i < 3; i++) {
474                 if (htype & flag_types[i]) {
475                         BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
476                                 BMO_elem_flag_disable(bm, ele, oflag);
477                         }
478                 }
479         }
480 }
481
482 int BMO_slot_buf_count(struct BMesh *UNUSED(bm), struct BMOperator *op, const char *slotname)
483 {
484         BMOpSlot *slot = BMO_slot_get(op, slotname);
485         
486         /* check if its actually a buffer */
487         if (!(slot->slottype > BMO_OP_SLOT_VEC))
488                 return 0;
489
490         return slot->len;
491 }
492
493 int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
494 {
495         BMOpSlot *slot = BMO_slot_get(op, slotname);
496         
497         /* check if its actually a buffer */
498         if (!(slot->slottype == BMO_OP_SLOT_MAPPING))
499                 return 0;
500
501         return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
502 }
503
504 #if 0
505 void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd)
506 {
507         BMOpSlot *slot = &op->slots[slotcode];
508         void *tmp;
509         ssize_t allocsize;
510         
511         /* check if its actually a buffer */
512         if (!(slot->slottype > BMO_OP_SLOT_VEC))
513                 return NULL;
514
515         if (slot->flag & BMOS_DYNAMIC_ARRAY) {
516                 if (slot->len >= slot->size) {
517                         slot->size = (slot->size + 1 + totadd) * 2;
518
519                         allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size;
520
521                         tmp = slot->data.buf;
522                         slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
523                         memcpy(slot->data.buf, tmp, allocsize);
524                         MEM_freeN(tmp);
525                 }
526
527                 slot->len += totadd;
528         }
529         else {
530                 slot->flag |= BMOS_DYNAMIC_ARRAY;
531                 slot->len += totadd;
532                 slot->size = slot->len + 2;
533
534                 allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len;
535
536                 tmp = slot->data.buf;
537                 slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
538                 memcpy(slot->data.buf, tmp, allocsize);
539         }
540
541         return slot->data.buf;
542 }
543 #endif
544
545 void BMO_slot_map_to_flag(struct BMesh *bm, struct BMOperator *op,
546                           const char *slotname, const short oflag)
547 {
548         GHashIterator it;
549         BMOpSlot *slot = BMO_slot_get(op, slotname);
550         BMHeader *ele;
551
552         /* sanity check */
553         if (slot->slottype != BMO_OP_SLOT_MAPPING) return;
554         if (!slot->data.ghash) return;
555
556         BLI_ghashIterator_init(&it, slot->data.ghash);
557         for ( ; (ele = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
558                 BMO_elem_flag_enable(bm, ele, oflag);
559         }
560 }
561
562 static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slotname, int len)
563 {
564         BMOpSlot *slot = BMO_slot_get(op, slotname);
565
566         /* check if its actually a buffer */
567         if (!(slot->slottype > BMO_OP_SLOT_VEC))
568                 return NULL;
569         
570         slot->len = len;
571         if (len)
572                 slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slottype] * len);
573         return slot->data.buf;
574 }
575
576 /*
577  * BMO_ALL_TO_SLOT
578  *
579  * Copies all elements of a certain type into an operator slot.
580  *
581  */
582
583 static void BMO_slot_from_all(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
584 {
585         BMIter elements;
586         BMHeader *e;
587         BMOpSlot *output = BMO_slot_get(op, slotname);
588         int totelement = 0, i = 0;
589         
590         if (htype & BM_VERT) totelement += bm->totvert;
591         if (htype & BM_EDGE) totelement += bm->totedge;
592         if (htype & BM_FACE) totelement += bm->totface;
593
594         if (totelement) {
595                 bmo_slot_buffer_alloc(op, slotname, totelement);
596
597                 if (htype & BM_VERT) {
598                         for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
599                                 ((BMHeader **)output->data.p)[i] = e;
600                                 i++;
601                         }
602                 }
603
604                 if (htype & BM_EDGE) {
605                         for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
606                                 ((BMHeader **)output->data.p)[i] = e;
607                                 i++;
608                         }
609                 }
610
611                 if (htype & BM_FACE) {
612                         for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
613                                 ((BMHeader **)output->data.p)[i] = e;
614                                 i++;
615                         }
616                 }
617         }
618 }
619
620 /*
621  * BMO_HEADERFLAG_TO_SLOT
622  *
623  * Copies elements of a certain type, which have a certain header flag set
624  * into a slot for an operator.
625  */
626
627 void BMO_slot_from_hflag(BMesh *bm, BMOperator *op, const char *slotname,
628                          const char hflag, const char htype)
629 {
630         BMIter elements;
631         BMHeader *e;
632         BMOpSlot *output = BMO_slot_get(op, slotname);
633         int totelement = 0, i = 0;
634         
635         totelement = BM_mesh_count_flag(bm, htype, hflag, 1);
636
637         if (totelement) {
638                 bmo_slot_buffer_alloc(op, slotname, totelement);
639
640                 if (htype & BM_VERT) {
641                         for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
642                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
643                                         ((BMHeader **)output->data.p)[i] = e;
644                                         i++;
645                                 }
646                         }
647                 }
648
649                 if (htype & BM_EDGE) {
650                         for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
651                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
652                                         ((BMHeader **)output->data.p)[i] = e;
653                                         i++;
654                                 }
655                         }
656                 }
657
658                 if (htype & BM_FACE) {
659                         for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
660                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
661                                         ((BMHeader **)output->data.p)[i] = e;
662                                         i++;
663                                 }
664                         }
665                 }
666         }
667         else {
668                 output->len = 0;
669         }
670 }
671
672 /*
673  * BMO_FLAG_TO_SLOT
674  *
675  * Copies elements of a certain type, which have a certain flag set
676  * into an output slot for an operator.
677  */
678 void BMO_slot_from_flag(BMesh *bm, BMOperator *op, const char *slotname,
679                         const short oflag, const char htype)
680 {
681         BMIter elements;
682         BMHeader *e;
683         BMOpSlot *output = BMO_slot_get(op, slotname);
684         int totelement = BMO_mesh_flag_count(bm, oflag, htype), i = 0;
685
686         if (totelement) {
687                 bmo_slot_buffer_alloc(op, slotname, totelement);
688
689                 if (htype & BM_VERT) {
690                         for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
691                                 if (BMO_elem_flag_test(bm, e, oflag)) {
692                                         ((BMHeader **)output->data.p)[i] = e;
693                                         i++;
694                                 }
695                         }
696                 }
697
698                 if (htype & BM_EDGE) {
699                         for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
700                                 if (BMO_elem_flag_test(bm, e, oflag)) {
701                                         ((BMHeader **)output->data.p)[i] = e;
702                                         i++;
703                                 }
704                         }
705                 }
706
707                 if (htype & BM_FACE) {
708                         for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
709                                 if (BMO_elem_flag_test(bm, e, oflag)) {
710                                         ((BMHeader **)output->data.p)[i] = e;
711                                         i++;
712                                 }
713                         }
714                 }
715         }
716         else {
717                 output->len = 0;
718         }
719 }
720
721 /*
722  *
723  * BMO_FLAG_BUFFER
724  *
725  * Header Flags elements in a slots buffer, automatically
726  * using the selection API where appropriate.
727  */
728 void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slotname,
729                                   const char hflag, const char htype)
730 {
731         BMOpSlot *slot = BMO_slot_get(op, slotname);
732         BMHeader **data =  slot->data.p;
733         int i;
734         
735         for (i = 0; i < slot->len; i++) {
736                 if (!(htype & data[i]->htype))
737                         continue;
738
739                 if (hflag & BM_ELEM_SELECT) {
740                         BM_elem_select_set(bm, data[i], TRUE);
741                 }
742                 BM_elem_flag_enable(data[i], hflag);
743         }
744 }
745
746 /*
747  *
748  * BMO_FLAG_BUFFER
749  *
750  * Removes flags from elements in a slots buffer, automatically
751  * using the selection API where appropriate.
752  */
753 void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slotname,
754                                    const char hflag, const char htype)
755 {
756         BMOpSlot *slot = BMO_slot_get(op, slotname);
757         BMHeader **data =  slot->data.p;
758         int i;
759         
760         for (i = 0; i < slot->len; i++) {
761                 if (!(htype & data[i]->htype))
762                         continue;
763
764                 if (hflag & BM_ELEM_SELECT) {
765                         BM_elem_select_set(bm, data[i], FALSE);
766                 }
767
768                 BM_elem_flag_disable(data[i], hflag);
769         }
770 }
771 int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
772 {
773         int count = 0;
774
775         if (v->e) {
776                 BMEdge *curedge;
777                 const int len = bmesh_disk_count(v);
778                 int i;
779                 
780                 for (i = 0, curedge = v->e; i < len; i++) {
781                         if (BMO_elem_flag_test(bm, curedge, oflag))
782                                 count++;
783                         curedge = bmesh_disk_nextedge(curedge, v);
784                 }
785         }
786
787         return count;
788 }
789
790 /*
791  *
792  * BMO_FLAG_BUFFER
793  *
794  * Flags elements in a slots buffer
795  */
796 void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slotname,
797                           const short oflag, const char htype)
798 {
799         BMOpSlot *slot = BMO_slot_get(op, slotname);
800         BMHeader **data =  slot->data.p;
801         int i;
802         
803         for (i = 0; i < slot->len; i++) {
804                 if (!(htype & data[i]->htype))
805                         continue;
806
807                 BMO_elem_flag_enable(bm, data[i], oflag);
808         }
809 }
810
811 /*
812  *
813  * BMO_FLAG_BUFFER
814  *
815  * Removes flags from elements in a slots buffer
816  */
817 void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slotname,
818                                 const short oflag, const char htype)
819 {
820         BMOpSlot *slot = BMO_slot_get(op, slotname);
821         BMHeader **data =  slot->data.p;
822         int i;
823         
824         for (i = 0; i < slot->len; i++) {
825                 if (!(htype & data[i]->htype))
826                         continue;
827
828                 BMO_elem_flag_disable(bm, data[i], oflag);
829         }
830 }
831
832
833 /*
834  *
835  *      ALLOC/FREE FLAG LAYER
836  *
837  *  Used by operator stack to free/allocate
838  *  private flag data. This is allocated
839  *  using a mempool so the allocation/frees
840  *  should be quite fast.
841  *
842  *  BMESH_TODO:
843  *      Investigate not freeing flag layers until
844  *  all operators have been executed. This would
845  *  save a lot of realloc potentially.
846  */
847 static void bmo_flag_layer_alloc(BMesh *bm)
848 {
849         BMHeader *ele;
850         /* set the index values since we are looping over all data anyway,
851          * may save time later on */
852         int i;
853
854         BMIter iter;
855         BLI_mempool *oldpool = bm->toolflagpool;                /* old flag pool */
856         BLI_mempool *newpool;
857         void *oldflags;
858
859         /* store memcpy size for reuse */
860         const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
861         
862         bm->totflags++;
863
864         /* allocate new flag poo */
865         bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, FALSE, FALSE);
866         
867         /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
868         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
869                 oldflags = ele->flags;
870                 ele->flags = BLI_mempool_calloc(newpool);
871                 memcpy(ele->flags, oldflags, old_totflags_size);
872                 BM_elem_index_set(ele, i); /* set_inline */
873         }
874         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
875                 oldflags = ele->flags;
876                 ele->flags = BLI_mempool_calloc(newpool);
877                 memcpy(ele->flags, oldflags, old_totflags_size);
878                 BM_elem_index_set(ele, i); /* set_inline */
879         }
880         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
881                 oldflags = ele->flags;
882                 ele->flags = BLI_mempool_calloc(newpool);
883                 memcpy(ele->flags, oldflags, old_totflags_size);
884                 BM_elem_index_set(ele, i); /* set_inline */
885         }
886
887         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
888
889         BLI_mempool_destroy(oldpool);
890 }
891
892 static void bmo_flag_layer_free(BMesh *bm)
893 {
894         BMHeader *ele;
895         /* set the index values since we are looping over all data anyway,
896          * may save time later on */
897         int i;
898
899         BMIter iter;
900         BLI_mempool *oldpool = bm->toolflagpool;
901         BLI_mempool *newpool;
902         void *oldflags;
903         
904         /* store memcpy size for reuse */
905         const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
906
907         /* de-increment the totflags first.. */
908         bm->totflags--;
909         /* allocate new flag poo */
910         bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, TRUE, FALSE);
911         
912         /* now go through and memcpy all the flag */
913         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
914                 oldflags = ele->flags;
915                 ele->flags = BLI_mempool_calloc(newpool);
916                 memcpy(ele->flags, oldflags, new_totflags_size);
917                 BM_elem_index_set(ele, i); /* set_inline */
918         }
919         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
920                 oldflags = ele->flags;
921                 ele->flags = BLI_mempool_calloc(newpool);
922                 memcpy(ele->flags, oldflags, new_totflags_size);
923                 BM_elem_index_set(ele, i); /* set_inline */
924         }
925         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
926                 oldflags = ele->flags;
927                 ele->flags = BLI_mempool_calloc(newpool);
928                 memcpy(ele->flags, oldflags, new_totflags_size);
929                 BM_elem_index_set(ele, i); /* set_inline */
930         }
931
932         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
933
934         BLI_mempool_destroy(oldpool);
935 }
936
937 static void bmo_flag_layer_clear(BMesh *bm)
938 {
939         BMHeader *ele;
940         /* set the index values since we are looping over all data anyway,
941          * may save time later on */
942         int i;
943
944         BMIter iter;
945         const int totflags_offset = bm->totflags - 1;
946
947         /* now go through and memcpy all the flag */
948         for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
949                 memset(ele->flags + totflags_offset, 0, sizeof(BMFlagLayer));
950                 BM_elem_index_set(ele, i); /* set_inline */
951         }
952         for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
953                 memset(ele->flags + totflags_offset, 0, sizeof(BMFlagLayer));
954                 BM_elem_index_set(ele, i); /* set_inline */
955         }
956         for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
957                 memset(ele->flags + totflags_offset, 0, sizeof(BMFlagLayer));
958                 BM_elem_index_set(ele, i); /* set_inline */
959         }
960
961         bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
962 }
963
964 void *BMO_slot_elem_first(BMOperator *op, const char *slotname)
965 {
966         BMOpSlot *slot = BMO_slot_get(op, slotname);
967         
968         if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
969                 return NULL;
970
971         return slot->data.buf ? *(void **)slot->data.buf : NULL;
972 }
973
974 void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
975                    const char *slotname, const char restrictmask)
976 {
977         BMOpSlot *slot = BMO_slot_get(op, slotname);
978
979         memset(iter, 0, sizeof(BMOIter));
980
981         iter->slot = slot;
982         iter->cur = 0;
983         iter->restrictmask = restrictmask;
984
985         if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
986                 if (iter->slot->data.ghash) {
987                         BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
988                 }
989                 else {
990                         return NULL;
991                 }
992         }
993
994         return BMO_iter_step(iter);
995 }
996
997 void *BMO_iter_step(BMOIter *iter)
998 {
999         if (iter->slot->slottype == BMO_OP_SLOT_ELEMENT_BUF) {
1000                 BMHeader *h;
1001
1002                 if (iter->cur >= iter->slot->len) {
1003                         return NULL;
1004                 }
1005
1006                 h = ((void **)iter->slot->data.buf)[iter->cur++];
1007                 while (!(iter->restrictmask & h->htype)) {
1008                         if (iter->cur >= iter->slot->len) {
1009                                 return NULL;
1010                         }
1011
1012                         h = ((void **)iter->slot->data.buf)[iter->cur++];
1013                 }
1014
1015                 return h;
1016         }
1017         else if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1018                 struct BMOElemMapping *map;
1019                 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1020                 map = BLI_ghashIterator_getValue(&iter->giter);
1021                 
1022                 iter->val = map + 1;
1023
1024                 BLI_ghashIterator_step(&iter->giter);
1025
1026                 return ret;
1027         }
1028
1029         return NULL;
1030 }
1031
1032 /* used for iterating over mapping */
1033 void *BMO_iter_map_value(BMOIter *iter)
1034 {
1035         return iter->val;
1036 }
1037
1038 void *BMO_iter_map_value_p(BMOIter *iter)
1039 {
1040         return *((void **)iter->val);
1041 }
1042
1043 float BMO_iter_map_value_f(BMOIter *iter)
1044 {
1045         return *((float *)iter->val);
1046 }
1047
1048 /* error syste */
1049 typedef struct BMOpError {
1050         struct BMOpError *next, *prev;
1051         int errorcode;
1052         BMOperator *op;
1053         const char *msg;
1054 } BMOpError;
1055
1056 void BMO_error_clear(BMesh *bm)
1057 {
1058         while (BMO_error_pop(bm, NULL, NULL));
1059 }
1060
1061 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1062 {
1063         BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1064         
1065         err->errorcode = errcode;
1066         if (!msg) msg = bmo_error_messages[errcode];
1067         err->msg = msg;
1068         err->op = owner;
1069         
1070         BLI_addhead(&bm->errorstack, err);
1071 }
1072
1073 int BMO_error_occurred(BMesh *bm)
1074 {
1075         return bm->errorstack.first != NULL;
1076 }
1077
1078 /* returns error code or 0 if no erro */
1079 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1080 {
1081         BMOpError *err = bm->errorstack.first;
1082         if (!err) {
1083                 return 0;
1084         }
1085
1086         if (msg) *msg = err->msg;
1087         if (op) *op = err->op;
1088         
1089         return err->errorcode;
1090 }
1091
1092 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1093 {
1094         int errorcode = BMO_error_get(bm, msg, op);
1095         
1096         if (errorcode) {
1097                 BMOpError *err = bm->errorstack.first;
1098                 
1099                 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1100                 MEM_freeN(err);
1101         }
1102
1103         return errorcode;
1104 }
1105
1106 /* example:
1107  * BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_ELEM_SELECT);
1108  *
1109  *  d - int
1110  *  i - int
1111  *  f - float
1112  *  hv - header flagged verts
1113  *  he - header flagged edges
1114  *  hf - header flagged faces
1115  *  fv - flagged verts
1116  *  fe - flagged edges
1117  *  ff - flagged faces
1118  */
1119
1120 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1121
1122 static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name)
1123 {
1124         int i;
1125
1126         for (i = 0; def->slottypes[i].type; i++) {
1127                 if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
1128                         return i;
1129                 }
1130         }
1131
1132         return -1;
1133 }
1134
1135 static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name)
1136 {
1137         int i = bmesh_name_to_slotcode(def, name);
1138         if (i < 0) {
1139                 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1140         }
1141
1142         return i;
1143 }
1144
1145 static int bmesh_opname_to_opcode(const char *opname)
1146 {
1147         int i;
1148
1149         for (i = 0; i < bmesh_total_ops; i++) {
1150                 if (!strcmp(opname, opdefines[i]->name)) {
1151                         return i;
1152                 }
1153         }
1154
1155         fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1156         return -1;
1157 }
1158
1159 int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1160 {
1161         BMOpDefine *def;
1162         char *opname, *ofmt, *fmt;
1163         char slotname[64] = {0};
1164         int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, ret, type, state;
1165         int noslot = 0;
1166
1167
1168         /* basic useful info to help find where bmop formatting strings fail */
1169         int lineno = -1;
1170 #   define GOTO_ERROR { lineno = __LINE__; goto error; }
1171
1172
1173         /* we muck around in here, so dup i */
1174         fmt = ofmt = BLI_strdup(_fmt);
1175         
1176         /* find operator nam */
1177         i = strcspn(fmt, " \t");
1178
1179         opname = fmt;
1180         if (!opname[i]) noslot = 1;
1181         opname[i] = '\0';
1182
1183         fmt += i + (noslot ? 0 : 1);
1184         
1185         i = bmesh_opname_to_opcode(opname);
1186
1187         if (i == -1) {
1188                 MEM_freeN(ofmt);
1189                 return FALSE;
1190         }
1191
1192         BMO_op_init(bm, op, opname);
1193         def = opdefines[i];
1194         
1195         i = 0;
1196         state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1197
1198         while (*fmt) {
1199                 if (state) {
1200                         /* jump past leading whitespac */
1201                         i = strspn(fmt, " \t");
1202                         fmt += i;
1203                         
1204                         /* ignore trailing whitespac */
1205                         if (!fmt[i])
1206                                 break;
1207
1208                         /* find end of slot name.  currently this is
1209                          * a little flexible, allowing "slot=%f",
1210                          * "slot %f", "slot%f", and "slot\t%f". */
1211                         i = strcspn(fmt, "= \t%");
1212                         if (!fmt[i]) GOTO_ERROR;
1213
1214                         fmt[i] = 0;
1215
1216                         if (bmesh_name_to_slotcode_check(def, fmt) < 0) GOTO_ERROR;
1217                         
1218                         BLI_strncpy(slotname, fmt, sizeof(slotname));
1219                         
1220                         state = 0;
1221                         fmt += i;
1222                 }
1223                 else {
1224                         switch (*fmt) {
1225                                 case ' ':
1226                                 case '\t':
1227                                 case '=':
1228                                 case '%':
1229                                         break;
1230                                 case 'm': {
1231                                         int size, c;
1232
1233                                         c = NEXT_CHAR(fmt);
1234                                         fmt++;
1235
1236                                         if (c == '3') size = 3;
1237                                         else if (c == '4') size = 4;
1238                                         else GOTO_ERROR;
1239
1240                                         BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
1241                                         state = 1;
1242                                         break;
1243                                 }
1244                                 case 'v': {
1245                                         BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
1246                                         state = 1;
1247                                         break;
1248                                 }
1249                                 case 'e': {
1250                                         BMHeader *ele = va_arg(vlist, void *);
1251                                         BMOpSlot *slot = BMO_slot_get(op, slotname);
1252
1253                                         slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1254                                         slot->len = 1;
1255                                         *((void **)slot->data.buf) = ele;
1256
1257                                         state = 1;
1258                                         break;
1259                                 }
1260                                 case 's': {
1261                                         BMOperator *op2 = va_arg(vlist, void *);
1262                                         const char *slotname2 = va_arg(vlist, char *);
1263
1264                                         BMO_slot_copy(op2, op, slotname2, slotname);
1265                                         state = 1;
1266                                         break;
1267                                 }
1268                                 case 'i':
1269                                 case 'd':
1270                                         BMO_slot_int_set(op, slotname, va_arg(vlist, int));
1271                                         state = 1;
1272                                         break;
1273                                 case 'p':
1274                                         BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
1275                                         state = 1;
1276                                         break;
1277                                 case 'f':
1278                                 case 'h':
1279                                 case 'a':
1280                                         type = *fmt;
1281
1282                                         if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\t' || NEXT_CHAR(fmt) == '\0') {
1283                                                 BMO_slot_float_set(op, slotname, va_arg(vlist, double));
1284                                         }
1285                                         else {
1286                                                 ret = 0;
1287                                                 stop = 0;
1288                                                 while (1) {
1289                                                         switch (NEXT_CHAR(fmt)) {
1290                                                                 case 'f': ret |= BM_FACE; break;
1291                                                                 case 'e': ret |= BM_EDGE; break;
1292                                                                 case 'v': ret |= BM_VERT; break;
1293                                                                 default:
1294                                                                         stop = 1;
1295                                                                         break;
1296                                                         }
1297                                                         if (stop) {
1298                                                                 break;
1299                                                         }
1300
1301                                                         fmt++;
1302                                                 }
1303
1304                                                 if (type == 'h') {
1305                                                         BMO_slot_from_hflag(bm, op, slotname, va_arg(vlist, int), ret);
1306                                                 }
1307                                                 else if (type == 'a') {
1308                                                         BMO_slot_from_all(bm, op, slotname, ret);
1309                                                 }
1310                                                 else {
1311                                                         BMO_slot_from_flag(bm, op, slotname, va_arg(vlist, int), ret);
1312                                                 }
1313                                         }
1314
1315                                         state = 1;
1316                                         break;
1317                                 default:
1318                                         fprintf(stderr,
1319                                                 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1320                                                 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1321                                         break;
1322                         }
1323                 }
1324                 fmt++;
1325         }
1326
1327         MEM_freeN(ofmt);
1328         return TRUE;
1329 error:
1330
1331         /* non urgent todo - explain exactly what is failing */
1332         fprintf(stderr,
1333                 "%s: error parsing formatting string, %d in '%s'\n    see - %s:%d\n",
1334                 __func__, (int)(fmt - ofmt), _fmt, __FILE__, lineno);
1335         MEM_freeN(ofmt);
1336
1337         BMO_op_finish(bm, op);
1338         return FALSE;
1339
1340 #undef GOTO_ERROR
1341
1342 }
1343
1344
1345 int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1346 {
1347         va_list list;
1348
1349         va_start(list, fmt);
1350         if (!BMO_op_vinitf(bm, op, fmt, list)) {
1351                 printf("%s: failed\n", __func__);
1352                 va_end(list);
1353                 return FALSE;
1354         }
1355         va_end(list);
1356
1357         return TRUE;
1358 }
1359
1360 int BMO_op_callf(BMesh *bm, const char *fmt, ...)
1361 {
1362         va_list list;
1363         BMOperator op;
1364
1365         va_start(list, fmt);
1366         if (!BMO_op_vinitf(bm, &op, fmt, list)) {
1367                 printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1368                 va_end(list);
1369                 return FALSE;
1370         }
1371
1372         BMO_op_exec(bm, &op);
1373         BMO_op_finish(bm, &op);
1374
1375         va_end(list);
1376         return TRUE;
1377 }