2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
20 * ***** END GPL LICENSE BLOCK *****
23 /** \file blender/bmesh/intern/bmesh_operators.c
26 * BMesh operator access.
29 #include "MEM_guardedalloc.h"
31 #include "BLI_utildefines.h"
32 #include "BLI_string.h"
34 #include "BLI_memarena.h"
35 #include "BLI_mempool.h"
36 #include "BLI_listbase.h"
37 #include "BLI_array.h"
40 #include "bmesh_private.h"
45 /* forward declarations */
46 static void alloc_flag_layer(BMesh *bm);
47 static void free_flag_layer(BMesh *bm);
48 static void clear_flag_layer(BMesh *bm);
49 static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name);
50 static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name);
51 static int bmesh_opname_to_opcode(const char *opname);
53 static const char *bmop_error_messages[] = {
55 "Self intersection error",
56 "Could not dissolve vert",
57 "Could not connect vertices",
58 "Could not traverse mesh",
59 "Could not dissolve faces",
60 "Could not dissolve vertices",
62 "Can not deal with non-manifold geometry",
64 "Internal mesh error",
68 /* operator slot type information - size of one element of the type given. */
69 const int BMOP_OPSLOT_TYPEINFO[] = {
77 sizeof(void *), /* pointer buffer */
78 sizeof(BMOElemMapping)
81 /* Dummy slot so there is something to return when slot name lookup fails */
82 static BMOpSlot BMOpEmptySlot = {0};
84 void BMO_Set_OpFlag(BMesh *UNUSED(bm), BMOperator *op, const int flag)
89 void BMO_Clear_OpFlag(BMesh *UNUSED(bm), BMOperator *op, const int flag)
97 * Pushes the opstack down one level
98 * and allocates a new flag layer if
101 void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
105 /* add flag layer, if appropriate */
106 if (bm->stackdepth > 1)
107 alloc_flag_layer(bm);
109 clear_flag_layer(bm);
115 * Pops the opstack one level
116 * and frees a flag layer if appropriate
117 * BMESH_TODO: investigate NOT freeing flag
120 void BMO_pop(BMesh *bm)
122 if (bm->stackdepth > 1)
129 * BMESH OPSTACK INIT OP
131 * Initializes an operator structure
134 void BMO_Init_Op(BMesh *bm, BMOperator *op, const char *opname)
136 int i, opcode = bmesh_opname_to_opcode(opname);
139 BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
145 opcode = 0; /* error!, already printed, have a better way to handle this? */
148 memset(op, 0, sizeof(BMOperator));
150 op->flag = opdefines[opcode]->flag;
152 /* initialize the operator slot types */
153 for (i = 0; opdefines[opcode]->slottypes[i].type; i++) {
154 op->slots[i].slottype = opdefines[opcode]->slottypes[i].type;
155 op->slots[i].index = i;
159 op->exec = opdefines[opcode]->exec;
161 /* memarena, used for operator's slot buffers */
162 op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bmesh operator");
163 BLI_memarena_use_calloc (op->arena);
167 * BMESH OPSTACK EXEC OP
169 * Executes a passed in operator. This handles
170 * the allocation and freeing of temporary flag
171 * layers and starting/stopping the modelling
172 * loop. Can be called from other operators
173 * exec callbacks as well.
175 void BMO_Exec_Op(BMesh *bm, BMOperator *op)
180 if (bm->stackdepth == 2)
181 bmesh_begin_edit(bm, op->flag);
184 if (bm->stackdepth == 2)
185 bmesh_end_edit(bm, op->flag);
191 * BMESH OPSTACK FINISH OP
193 * Does housekeeping chores related to finishing
196 void BMO_Finish_Op(BMesh *bm, BMOperator *op)
201 for (i = 0; opdefines[op->type]->slottypes[i].type; i++) {
202 slot = &op->slots[i];
203 if (slot->slottype == BMOP_OPSLOT_MAPPING) {
204 if (slot->data.ghash)
205 BLI_ghash_free(slot->data.ghash, NULL, NULL);
209 BLI_memarena_free(op->arena);
212 BM_ELEM_INDEX_VALIDATE(bm, "post bmo", opdefines[op->type]->name);
219 * BMESH OPSTACK HAS SLOT
221 * Returns 1 if the named slot exists on the given operator,
222 * otherwise returns 0.
224 int BMO_HasSlot(BMOperator *op, const char *slotname)
226 int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname);
227 return (slotcode >= 0);
231 * BMESH OPSTACK GET SLOT
233 * Returns a pointer to the slot of
236 BMOpSlot *BMO_GetSlot(BMOperator *op, const char *slotname)
238 int slotcode = bmesh_name_to_slotcode_check(opdefines[op->type], slotname);
241 return &BMOpEmptySlot;
244 return &(op->slots[slotcode]);
248 * BMESH OPSTACK COPY SLOT
250 * Copies data from one slot to another
252 void BMO_CopySlot(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
254 BMOpSlot *source_slot = BMO_GetSlot(source_op, src);
255 BMOpSlot *dest_slot = BMO_GetSlot(dest_op, dst);
257 if (source_slot == dest_slot)
260 if (source_slot->slottype != dest_slot->slottype)
263 if (dest_slot->slottype > BMOP_OPSLOT_VEC) {
264 if (dest_slot->slottype != BMOP_OPSLOT_MAPPING) {
266 dest_slot->data.buf = NULL;
267 dest_slot->len = source_slot->len;
268 if (dest_slot->len) {
269 const int slot_alloc_size = BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
270 dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
271 memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
276 BMOElemMapping *srcmap, *dstmap;
279 if (!source_slot->data.ghash) return;
281 if (!dest_slot->data.ghash) {
282 dest_slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
283 BLI_ghashutil_ptrcmp, "bmesh operator 2");
286 BLI_ghashIterator_init(&it, source_slot->data.ghash);
287 for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
288 BLI_ghashIterator_step(&it))
290 dstmap = BLI_memarena_alloc(dest_op->arena, sizeof(*dstmap) + srcmap->len);
292 dstmap->element = srcmap->element;
293 dstmap->len = srcmap->len;
294 memcpy(dstmap + 1, srcmap + 1, srcmap->len);
296 BLI_ghash_insert(dest_slot->data.ghash, dstmap->element, dstmap);
301 dest_slot->data = source_slot->data;
306 * BMESH OPSTACK SET XXX
308 * Sets the value of a slot depending on it's type
312 void BMO_Set_Float(BMOperator *op, const char *slotname, float f)
314 BMOpSlot *slot = BMO_GetSlot(op, slotname);
315 if (!(slot->slottype == BMOP_OPSLOT_FLT))
321 void BMO_Set_Int(BMOperator *op, const char *slotname, int i)
323 BMOpSlot *slot = BMO_GetSlot(op, slotname);
324 if (!(slot->slottype == BMOP_OPSLOT_INT))
330 /* only supports square mats */
331 void BMO_Set_Mat(struct BMOperator *op, const char *slotname, float *mat, int size)
333 BMOpSlot *slot = BMO_GetSlot(op, slotname);
334 if (!(slot->slottype == BMOP_OPSLOT_MAT))
338 slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
341 memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
343 else if (size == 3) {
344 copy_m4_m3(slot->data.p, (float (*)[3])mat);
347 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
349 memset(slot->data.p, 0, sizeof(float) * 4 * 4);
354 void BMO_Get_Mat4(struct BMOperator *op, const char *slotname, float mat[4][4])
356 BMOpSlot *slot = BMO_GetSlot(op, slotname);
357 if (!(slot->slottype == BMOP_OPSLOT_MAT))
360 memcpy(mat, slot->data.p, sizeof(float) * 4 * 4);
363 void BMO_Get_Mat3(struct BMOperator *op, const char *slotname, float mat[3][3])
365 BMOpSlot *slot = BMO_GetSlot(op, slotname);
366 if (!(slot->slottype == BMOP_OPSLOT_MAT))
369 copy_m3_m4(mat, slot->data.p);
372 void BMO_Set_Pnt(BMOperator *op, const char *slotname, void *p)
374 BMOpSlot *slot = BMO_GetSlot(op, slotname);
375 if (!(slot->slottype == BMOP_OPSLOT_PNT))
381 void BMO_Set_Vec(BMOperator *op, const char *slotname, const float vec[3])
383 BMOpSlot *slot = BMO_GetSlot(op, slotname);
384 if (!(slot->slottype == BMOP_OPSLOT_VEC))
387 copy_v3_v3(slot->data.vec, vec);
391 float BMO_Get_Float(BMOperator *op, const char *slotname)
393 BMOpSlot *slot = BMO_GetSlot(op, slotname);
394 if (!(slot->slottype == BMOP_OPSLOT_FLT))
400 int BMO_Get_Int(BMOperator *op, const char *slotname)
402 BMOpSlot *slot = BMO_GetSlot(op, slotname);
403 if (!(slot->slottype == BMOP_OPSLOT_INT))
410 void *BMO_Get_Pnt(BMOperator *op, const char *slotname)
412 BMOpSlot *slot = BMO_GetSlot(op, slotname);
413 if (!(slot->slottype == BMOP_OPSLOT_PNT))
419 void BMO_Get_Vec(BMOperator *op, const char *slotname, float r_vec[3])
421 BMOpSlot *slot = BMO_GetSlot(op, slotname);
422 if (!(slot->slottype == BMOP_OPSLOT_VEC))
425 copy_v3_v3(r_vec, slot->data.vec);
431 * Counts the number of elements of a certain type that
432 * have a specific flag set.
436 int BMO_CountFlag(BMesh *bm, const int oflag, const char htype)
442 if (htype & BM_VERT) {
443 for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
444 if (BMO_TestFlag(bm, e, oflag))
448 if (htype & BM_EDGE) {
449 for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
450 if (BMO_TestFlag(bm, e, oflag))
454 if (htype & BM_FACE) {
455 for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
456 if (BMO_TestFlag(bm, e, oflag))
464 void BMO_Clear_Flag_All(BMesh *bm, BMOperator *UNUSED(op), const char htype, const int oflag)
466 const char iter_types[3] = {BM_VERTS_OF_MESH,
470 const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
476 for (i = 0; i < 3; i++) {
477 if (htype & flag_types[i]) {
478 BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
479 BMO_ClearFlag(bm, ele, oflag);
485 int BMO_CountSlotBuf(struct BMesh *UNUSED(bm), struct BMOperator *op, const char *slotname)
487 BMOpSlot *slot = BMO_GetSlot(op, slotname);
489 /* check if its actually a buffer */
490 if (!(slot->slottype > BMOP_OPSLOT_VEC))
496 int BMO_CountSlotMap(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
498 BMOpSlot *slot = BMO_GetSlot(op, slotname);
500 /* check if its actually a buffer */
501 if (!(slot->slottype == BMOP_OPSLOT_MAPPING))
504 return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
508 void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd)
510 BMOpSlot *slot = &op->slots[slotcode];
513 /* check if its actually a buffer */
514 if (!(slot->slottype > BMOP_OPSLOT_VEC))
517 if (slot->flag & BMOS_DYNAMIC_ARRAY) {
518 if (slot->len >= slot->size) {
519 slot->size = (slot->size + 1 + totadd) * 2;
521 tmp = slot->data.buf;
522 slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size, "opslot dynamic array");
523 memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size);
530 slot->flag |= BMOS_DYNAMIC_ARRAY;
532 slot->size = slot->len + 2;
533 tmp = slot->data.buf;
534 slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len, "opslot dynamic array");
535 memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len);
538 return slot->data.buf;
542 void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op,
543 const char *slotname, const int oflag)
546 BMOpSlot *slot = BMO_GetSlot(op, slotname);
550 if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
551 if (!slot->data.ghash) return;
553 BLI_ghashIterator_init(&it, slot->data.ghash);
554 for ( ; (ele = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
555 BMO_SetFlag(bm, ele, oflag);
559 static void *alloc_slot_buffer(BMOperator *op, const char *slotname, int len)
561 BMOpSlot *slot = BMO_GetSlot(op, slotname);
563 /* check if its actually a buffer */
564 if (!(slot->slottype > BMOP_OPSLOT_VEC))
569 slot->data.buf = BLI_memarena_alloc(op->arena, BMOP_OPSLOT_TYPEINFO[slot->slottype] * len);
570 return slot->data.buf;
576 * Copies all elements of a certain type into an operator slot.
580 static void BMO_All_To_Slot(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
584 BMOpSlot *output = BMO_GetSlot(op, slotname);
585 int totelement = 0, i = 0;
587 if (htype & BM_VERT) totelement += bm->totvert;
588 if (htype & BM_EDGE) totelement += bm->totedge;
589 if (htype & BM_FACE) totelement += bm->totface;
592 alloc_slot_buffer(op, slotname, totelement);
594 if (htype & BM_VERT) {
595 for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
596 ((BMHeader **)output->data.p)[i] = e;
601 if (htype & BM_EDGE) {
602 for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
603 ((BMHeader **)output->data.p)[i] = e;
608 if (htype & BM_FACE) {
609 for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
610 ((BMHeader **)output->data.p)[i] = e;
618 * BMO_HEADERFLAG_TO_SLOT
620 * Copies elements of a certain type, which have a certain header flag set
621 * into a slot for an operator.
624 void BMO_HeaderFlag_To_Slot(BMesh *bm, BMOperator *op, const char *slotname,
625 const char hflag, const char htype)
629 BMOpSlot *output = BMO_GetSlot(op, slotname);
630 int totelement = 0, i = 0;
632 totelement = BM_CountFlag(bm, htype, hflag, 1);
635 alloc_slot_buffer(op, slotname, totelement);
637 if (htype & BM_VERT) {
638 for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
639 if (!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, hflag)) {
640 ((BMHeader **)output->data.p)[i] = e;
646 if (htype & BM_EDGE) {
647 for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
648 if (!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, hflag)) {
649 ((BMHeader **)output->data.p)[i] = e;
655 if (htype & BM_FACE) {
656 for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
657 if (!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, hflag)) {
658 ((BMHeader **)output->data.p)[i] = e;
672 * Copies elements of a certain type, which have a certain flag set
673 * into an output slot for an operator.
675 void BMO_Flag_To_Slot(BMesh *bm, BMOperator *op, const char *slotname,
676 const int oflag, const char htype)
680 BMOpSlot *output = BMO_GetSlot(op, slotname);
681 int totelement = BMO_CountFlag(bm, oflag, htype), i = 0;
684 alloc_slot_buffer(op, slotname, totelement);
686 if (htype & BM_VERT) {
687 for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
688 if (BMO_TestFlag(bm, e, oflag)) {
689 ((BMHeader **)output->data.p)[i] = e;
695 if (htype & BM_EDGE) {
696 for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
697 if (BMO_TestFlag(bm, e, oflag)) {
698 ((BMHeader **)output->data.p)[i] = e;
704 if (htype & BM_FACE) {
705 for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
706 if (BMO_TestFlag(bm, e, oflag)) {
707 ((BMHeader **)output->data.p)[i] = e;
722 * Header Flags elements in a slots buffer, automatically
723 * using the selection API where appropriate.
725 void BMO_HeaderFlag_Buffer(BMesh *bm, BMOperator *op, const char *slotname,
726 const char hflag, const char htype)
728 BMOpSlot *slot = BMO_GetSlot(op, slotname);
729 BMHeader **data = slot->data.p;
732 for (i = 0; i < slot->len; i++) {
733 if (!(htype & data[i]->htype))
736 if (hflag & BM_SELECT) {
737 BM_Select(bm, data[i], TRUE);
739 BM_SetHFlag(data[i], hflag);
747 * Removes flags from elements in a slots buffer, automatically
748 * using the selection API where appropriate.
750 void BMO_UnHeaderFlag_Buffer(BMesh *bm, BMOperator *op, const char *slotname,
751 const char hflag, const char htype)
753 BMOpSlot *slot = BMO_GetSlot(op, slotname);
754 BMHeader **data = slot->data.p;
757 for (i = 0; i < slot->len; i++) {
758 if (!(htype & data[i]->htype))
761 if (hflag & BM_SELECT) {
762 BM_Select(bm, data[i], FALSE);
765 BM_ClearHFlag(data[i], hflag);
768 int BMO_Vert_CountEdgeFlags(BMesh *bm, BMVert *v, const int oflag)
774 const int len = bmesh_disk_count(v);
777 for (i = 0, curedge = v->e; i < len; i++) {
778 if (BMO_TestFlag(bm, curedge, oflag))
780 curedge = bmesh_disk_nextedge(curedge, v);
791 * Flags elements in a slots buffer
793 void BMO_Flag_Buffer(BMesh *bm, BMOperator *op, const char *slotname,
794 const int oflag, const char htype)
796 BMOpSlot *slot = BMO_GetSlot(op, slotname);
797 BMHeader **data = slot->data.p;
800 for (i = 0; i < slot->len; i++) {
801 if (!(htype & data[i]->htype))
804 BMO_SetFlag(bm, data[i], oflag);
812 * Removes flags from elements in a slots buffer
814 void BMO_Unflag_Buffer(BMesh *bm, BMOperator *op, const char *slotname,
815 const int oflag, const char htype)
817 BMOpSlot *slot = BMO_GetSlot(op, slotname);
818 BMHeader **data = slot->data.p;
821 for (i = 0; i < slot->len; i++) {
822 if (!(htype & data[i]->htype))
825 BMO_ClearFlag(bm, data[i], oflag);
832 * ALLOC/FREE FLAG LAYER
834 * Used by operator stack to free/allocate
835 * private flag data. This is allocated
836 * using a mempool so the allocation/frees
837 * should be quite fast.
840 * Investigate not freeing flag layers until
841 * all operators have been executed. This would
842 * save a lot of realloc potentially.
844 static void alloc_flag_layer(BMesh *bm)
847 /* set the index values since we are looping over all data anyway,
848 * may save time later on */
852 BLI_mempool *oldpool = bm->toolflagpool; /* old flag pool */
853 BLI_mempool *newpool;
856 /* store memcpy size for reuse */
857 const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
861 /* allocate new flag poo */
862 bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, FALSE, FALSE);
864 /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
865 for (ele = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BMIter_Step(&iter), i++) {
866 oldflags = ele->flags;
867 ele->flags = BLI_mempool_calloc(newpool);
868 memcpy(ele->flags, oldflags, old_totflags_size);
869 BM_SetIndex(ele, i); /* set_inline */
871 for (ele = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BMIter_Step(&iter), i++) {
872 oldflags = ele->flags;
873 ele->flags = BLI_mempool_calloc(newpool);
874 memcpy(ele->flags, oldflags, old_totflags_size);
875 BM_SetIndex(ele, i); /* set_inline */
877 for (ele = BMIter_New(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BMIter_Step(&iter), i++) {
878 oldflags = ele->flags;
879 ele->flags = BLI_mempool_calloc(newpool);
880 memcpy(ele->flags, oldflags, old_totflags_size);
881 BM_SetIndex(ele, i); /* set_inline */
884 bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
886 BLI_mempool_destroy(oldpool);
889 static void free_flag_layer(BMesh *bm)
892 /* set the index values since we are looping over all data anyway,
893 * may save time later on */
897 BLI_mempool *oldpool = bm->toolflagpool;
898 BLI_mempool *newpool;
901 /* store memcpy size for reuse */
902 const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
904 /* de-increment the totflags first.. */
906 /* allocate new flag poo */
907 bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, TRUE, FALSE);
909 /* now go through and memcpy all the flag */
910 for (ele = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BMIter_Step(&iter), i++) {
911 oldflags = ele->flags;
912 ele->flags = BLI_mempool_calloc(newpool);
913 memcpy(ele->flags, oldflags, new_totflags_size);
914 BM_SetIndex(ele, i); /* set_inline */
916 for (ele = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BMIter_Step(&iter), i++) {
917 oldflags = ele->flags;
918 ele->flags = BLI_mempool_calloc(newpool);
919 memcpy(ele->flags, oldflags, new_totflags_size);
920 BM_SetIndex(ele, i); /* set_inline */
922 for (ele = BMIter_New(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BMIter_Step(&iter), i++) {
923 oldflags = ele->flags;
924 ele->flags = BLI_mempool_calloc(newpool);
925 memcpy(ele->flags, oldflags, new_totflags_size);
926 BM_SetIndex(ele, i); /* set_inline */
929 bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
931 BLI_mempool_destroy(oldpool);
934 static void clear_flag_layer(BMesh *bm)
944 /* now go through and memcpy all the flag */
945 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)) {
946 memset(v->head.flags + (bm->totflags - 1), 0, sizeof(BMFlagLayer));
948 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) {
949 memset(e->head.flags + (bm->totflags - 1), 0, sizeof(BMFlagLayer));
951 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) {
952 memset(f->head.flags + (bm->totflags - 1), 0, sizeof(BMFlagLayer));
956 void *BMO_FirstElem(BMOperator *op, const char *slotname)
958 BMOpSlot *slot = BMO_GetSlot(op, slotname);
960 if (slot->slottype != BMOP_OPSLOT_ELEMENT_BUF)
963 return slot->data.buf ? *(void **)slot->data.buf : NULL;
966 void *BMO_IterNew(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
967 const char *slotname, const char restrictmask)
969 BMOpSlot *slot = BMO_GetSlot(op, slotname);
971 memset(iter, 0, sizeof(BMOIter));
975 iter->restrictmask = restrictmask;
977 if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
978 if (iter->slot->data.ghash) {
979 BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
986 return BMO_IterStep(iter);
989 void *BMO_IterStep(BMOIter *iter)
991 if (iter->slot->slottype == BMOP_OPSLOT_ELEMENT_BUF) {
994 if (iter->cur >= iter->slot->len) {
998 h = ((void **)iter->slot->data.buf)[iter->cur++];
999 while (!(iter->restrictmask & h->htype)) {
1000 if (iter->cur >= iter->slot->len) {
1004 h = ((void **)iter->slot->data.buf)[iter->cur++];
1009 else if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
1010 struct BMOElemMapping *map;
1011 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1012 map = BLI_ghashIterator_getValue(&iter->giter);
1014 iter->val = map + 1;
1016 BLI_ghashIterator_step(&iter->giter);
1024 /* used for iterating over mapping */
1025 void *BMO_IterMapVal(BMOIter *iter)
1030 void *BMO_IterMapValp(BMOIter *iter)
1032 return *((void **)iter->val);
1035 float BMO_IterMapValf(BMOIter *iter)
1037 return *((float *)iter->val);
1041 typedef struct BMOpError {
1042 struct BMOpError *next, *prev;
1048 void BMO_ClearStack(BMesh *bm)
1050 while (BMO_PopError(bm, NULL, NULL));
1053 void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1055 BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1057 err->errorcode = errcode;
1058 if (!msg) msg = bmop_error_messages[errcode];
1062 BLI_addhead(&bm->errorstack, err);
1065 int BMO_HasError(BMesh *bm)
1067 return bm->errorstack.first != NULL;
1070 /* returns error code or 0 if no erro */
1071 int BMO_GetError(BMesh *bm, const char **msg, BMOperator **op)
1073 BMOpError *err = bm->errorstack.first;
1078 if (msg) *msg = err->msg;
1079 if (op) *op = err->op;
1081 return err->errorcode;
1084 int BMO_PopError(BMesh *bm, const char **msg, BMOperator **op)
1086 int errorcode = BMO_GetError(bm, msg, op);
1089 BMOpError *err = bm->errorstack.first;
1091 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1099 typedef struct BMOFlag {
1104 #define PAIR(f) {#f, f},fv
1105 static const char *bmesh_flags = {
1116 int bmesh_str_to_flag(const char *str)
1120 while (bmesh_flags[i]->name) {
1121 if (!strcmp(bmesh_flags[i]->name, str))
1122 return bmesh_flags[i]->flag;
1130 * BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_SELECT);
1135 * hv - header flagged verts
1136 * he - header flagged edges
1137 * hf - header flagged faces
1138 * fv - flagged verts
1139 * fe - flagged edges
1140 * ff - flagged faces
1143 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1145 static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name)
1149 for (i = 0; def->slottypes[i].type; i++) {
1150 if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
1158 static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name)
1160 int i = bmesh_name_to_slotcode(def, name);
1162 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1168 static int bmesh_opname_to_opcode(const char *opname)
1172 for (i = 0; i < bmesh_total_ops; i++) {
1173 if (!strcmp(opname, opdefines[i]->name)) {
1178 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1182 int BMO_VInitOpf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1185 char *opname, *ofmt, *fmt;
1186 char slotname[64] = {0};
1187 int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, ret, type, state;
1191 /* basic useful info to help find where bmop formatting strings fail */
1193 # define GOTO_ERROR { lineno = __LINE__; goto error; }
1196 /* we muck around in here, so dup i */
1197 fmt = ofmt = BLI_strdup(_fmt);
1199 /* find operator nam */
1200 i = strcspn(fmt, " \t");
1203 if (!opname[i]) noslot = 1;
1206 fmt += i + (noslot ? 0 : 1);
1208 i = bmesh_opname_to_opcode(opname);
1215 BMO_Init_Op(bm, op, opname);
1219 state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1223 /* jump past leading whitespac */
1224 i = strspn(fmt, " \t");
1227 /* ignore trailing whitespac */
1231 /* find end of slot name. currently this is
1232 * a little flexible, allowing "slot=%f",
1233 * "slot %f", "slot%f", and "slot\t%f". */
1234 i = strcspn(fmt, "= \t%");
1235 if (!fmt[i]) GOTO_ERROR;
1239 if (bmesh_name_to_slotcode_check(def, fmt) < 0) GOTO_ERROR;
1241 BLI_strncpy(slotname, fmt, sizeof(slotname));
1259 if (c == '3') size = 3;
1260 else if (c == '4') size = 4;
1263 BMO_Set_Mat(op, slotname, va_arg(vlist, void *), size);
1268 BMO_Set_Vec(op, slotname, va_arg(vlist, float *));
1273 BMHeader *ele = va_arg(vlist, void *);
1274 BMOpSlot *slot = BMO_GetSlot(op, slotname);
1276 slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1278 *((void **)slot->data.buf) = ele;
1284 BMOperator *op2 = va_arg(vlist, void *);
1285 const char *slotname2 = va_arg(vlist, char *);
1287 BMO_CopySlot(op2, op, slotname2, slotname);
1293 BMO_Set_Int(op, slotname, va_arg(vlist, int));
1297 BMO_Set_Pnt(op, slotname, va_arg(vlist, void *));
1305 if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\t' || NEXT_CHAR(fmt) == '\0') {
1306 BMO_Set_Float(op, slotname, va_arg(vlist, double));
1312 switch (NEXT_CHAR(fmt)) {
1313 case 'f': ret |= BM_FACE; break;
1314 case 'e': ret |= BM_EDGE; break;
1315 case 'v': ret |= BM_VERT; break;
1328 BMO_HeaderFlag_To_Slot(bm, op, slotname, va_arg(vlist, int), ret);
1330 else if (type == 'a') {
1331 BMO_All_To_Slot(bm, op, slotname, ret);
1334 BMO_Flag_To_Slot(bm, op, slotname, va_arg(vlist, int), ret);
1342 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1343 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1354 /* non urgent todo - explain exactly what is failing */
1356 "%s: error parsing formatting string, %d in '%s'\n see - %s:%d\n",
1357 __func__, (int)(fmt - ofmt), _fmt, __FILE__, lineno);
1360 BMO_Finish_Op(bm, op);
1368 int BMO_InitOpf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1372 va_start(list, fmt);
1373 if (!BMO_VInitOpf(bm, op, fmt, list)) {
1374 printf("%s: failed\n", __func__);
1383 int BMO_CallOpf(BMesh *bm, const char *fmt, ...)
1388 va_start(list, fmt);
1389 if (!BMO_VInitOpf(bm, &op, fmt, list)) {
1390 printf("%s: failed, format is:\n \"%s\"\n", __func__, fmt);
1395 BMO_Exec_Op(bm, &op);
1396 BMO_Finish_Op(bm, &op);
1405 * Toggles a flag for a certain element
1407 #ifdef BMO_ToggleFlag
1408 #undef BMO_ToggleFlag
1410 static void BMO_ToggleFlag(BMesh *bm, void *element, int oflag)
1412 BMHeader *head = element;
1413 head->flags[bm->stackdepth - 1].f ^= oflag;
1419 * Sets a flag for a certain element
1424 static void BMO_SetFlag(BMesh *bm, void *element, const int oflag)
1426 BMHeader *head = element;
1427 head->flags[bm->stackdepth - 1].f |= oflag;
1433 * Clears a specific flag from a given element
1435 #ifdef BMO_ClearFlag
1436 #undef BMO_ClearFlag
1438 static void BMO_ClearFlag(BMesh *bm, void *element, const int oflag)
1440 BMHeader *head = element;
1441 head->flags[bm->stackdepth - 1].f &= ~oflag;
1447 * Tests whether or not a flag is set for a specific element
1453 static int BMO_TestFlag(BMesh *bm, void *element, const int oflag)
1455 BMHeader *head = element;
1456 if (head->flags[bm->stackdepth - 1].f & oflag)