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"
38 #include "BLT_translation.h"
41 #include "intern/bmesh_private.h"
43 /* forward declarations */
44 static void bmo_flag_layer_alloc(BMesh *bm);
45 static void bmo_flag_layer_free(BMesh *bm);
46 static void bmo_flag_layer_clear(BMesh *bm);
47 static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
48 static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
50 static const char *bmo_error_messages[] = {
52 N_("Self intersection error"),
53 N_("Could not dissolve vert"),
54 N_("Could not connect vertices"),
55 N_("Could not traverse mesh"),
56 N_("Could not dissolve faces"),
57 N_("Tessellation error"),
58 N_("Cannot deal with non-manifold geometry"),
59 N_("Invalid selection"),
60 N_("Internal mesh error"),
63 BLI_STATIC_ASSERT(ARRAY_SIZE(bmo_error_messages) + 1 == BMERR_TOTAL, "message mismatch");
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 */
75 sizeof(float) * 3, /* 8: BMO_OP_SLOT_VEC */
76 sizeof(void *), /* 9: BMO_OP_SLOT_ELEMENT_BUF */
77 sizeof(void *) /* 10: BMO_OP_SLOT_MAPPING */
80 /* Dummy slot so there is something to return when slot name lookup fails */
81 // static BMOpSlot BMOpEmptySlot = {0};
83 void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
88 void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
94 * \brief BMESH OPSTACK PUSH
96 * Pushes the opstack down one level and allocates a new flag layer if appropriate.
98 void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
100 bm->toolflag_index++;
102 BLI_assert(bm->totflags > 0);
104 /* add flag layer, if appropriate */
105 if (bm->toolflag_index > 0)
106 bmo_flag_layer_alloc(bm);
108 bmo_flag_layer_clear(bm);
112 * \brief BMESH OPSTACK POP
114 * Pops the opstack one level and frees a flag layer if appropriate
116 * BMESH_TODO: investigate NOT freeing flag layers.
118 void BMO_pop(BMesh *bm)
120 if (bm->toolflag_index > 0)
121 bmo_flag_layer_free(bm);
123 bm->toolflag_index--;
127 /* use for both slot_types_in and slot_types_out */
128 static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args)
132 for (i = 0; slot_types[i].type; i++) {
133 slot = &slot_args[i];
134 slot->slot_name = slot_types[i].name;
135 slot->slot_type = slot_types[i].type;
136 slot->slot_subtype = slot_types[i].subtype;
137 // slot->index = i; // UNUSED
139 switch (slot->slot_type) {
140 case BMO_OP_SLOT_MAPPING:
141 slot->data.ghash = BLI_ghash_ptr_new("bmesh slot map hash");
149 static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args)
153 for (i = 0; slot_types[i].type; i++) {
154 slot = &slot_args[i];
155 switch (slot->slot_type) {
156 case BMO_OP_SLOT_MAPPING:
157 BLI_ghash_free(slot->data.ghash, NULL, NULL);
166 * \brief BMESH OPSTACK INIT OP
168 * Initializes an operator structure to a certain type
170 void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
172 int opcode = BMO_opcode_from_opname(opname);
175 BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
181 opcode = 0; /* error!, already printed, have a better way to handle this? */
184 memset(op, 0, sizeof(BMOperator));
186 op->type_flag = bmo_opdefines[opcode]->type_flag;
189 /* initialize the operator slot types */
190 bmo_op_slots_init(bmo_opdefines[opcode]->slot_types_in, op->slots_in);
191 bmo_op_slots_init(bmo_opdefines[opcode]->slot_types_out, op->slots_out);
194 op->exec = bmo_opdefines[opcode]->exec;
196 /* memarena, used for operator's slot buffers */
197 op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
198 BLI_memarena_use_calloc(op->arena);
202 * \brief BMESH OPSTACK EXEC OP
204 * Executes a passed in operator.
206 * This handles the allocation and freeing of temporary flag
207 * layers and starting/stopping the modeling loop.
208 * Can be called from other operators exec callbacks as well.
210 void BMO_op_exec(BMesh *bm, BMOperator *op)
212 /* allocate tool flags on demand */
213 BM_mesh_elem_toolflags_ensure(bm);
217 if (bm->toolflag_index == 1)
218 bmesh_edit_begin(bm, op->type_flag);
221 if (bm->toolflag_index == 1)
222 bmesh_edit_end(bm, op->type_flag);
228 * \brief BMESH OPSTACK FINISH OP
230 * Does housekeeping chores related to finishing up an operator.
232 void BMO_op_finish(BMesh *bm, BMOperator *op)
234 bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_in, op->slots_in);
235 bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_out, op->slots_out);
237 BLI_memarena_free(op->arena);
240 BM_ELEM_INDEX_VALIDATE(bm, "post bmo", bmo_opdefines[op->type]->opname);
242 /* avoid accidental re-use */
243 memset(op, 0xff, sizeof(*op));
250 * \brief BMESH OPSTACK HAS SLOT
252 * \return Success if the slot if found.
254 bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
256 int slot_code = bmo_name_to_slotcode(slot_args, identifier);
257 return (slot_code >= 0);
261 * \brief BMESH OPSTACK GET SLOT
263 * Returns a pointer to the slot of type 'slot_code'
265 BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
267 int slot_code = bmo_name_to_slotcode_check(slot_args, identifier);
269 if (UNLIKELY(slot_code < 0)) {
270 //return &BMOpEmptySlot;
272 return NULL; /* better crash */
275 return &slot_args[slot_code];
279 * \brief BMESH OPSTACK COPY SLOT
282 * Copies data from one slot to another.
285 BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
286 BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
287 struct MemArena *arena_dst)
289 BMOpSlot *slot_src = BMO_slot_get(slot_args_src, slot_name_src);
290 BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
292 if (slot_src == slot_dst)
295 BLI_assert(slot_src->slot_type == slot_dst->slot_type);
296 if (slot_src->slot_type != slot_dst->slot_type) {
300 if (slot_dst->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
302 slot_dst->data.buf = NULL;
303 slot_dst->len = slot_src->len;
305 /* check dest has all flags enabled that the source has */
306 const eBMOpSlotSubType_Elem src_elem_flag = (slot_src->slot_subtype.elem & BM_ALL_NOLOOP);
307 const eBMOpSlotSubType_Elem dst_elem_flag = (slot_dst->slot_subtype.elem & BM_ALL_NOLOOP);
309 if ((src_elem_flag | dst_elem_flag) == dst_elem_flag) {
314 const uint tot = slot_src->len;
317 BMElem **ele_src = (BMElem **)slot_src->data.buf;
318 for (i = 0; i < tot; i++, ele_src++) {
319 if ((*ele_src)->head.htype & dst_elem_flag) {
329 const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[slot_dst->slot_type] * slot_dst->len;
330 slot_dst->data.buf = BLI_memarena_alloc(arena_dst, slot_alloc_size);
331 if (slot_src->len == slot_dst->len) {
332 memcpy(slot_dst->data.buf, slot_src->data.buf, slot_alloc_size);
335 /* only copy compatible elements */
336 const uint tot = slot_src->len;
338 BMElem **ele_src = (BMElem **)slot_src->data.buf;
339 BMElem **ele_dst = (BMElem **)slot_dst->data.buf;
340 for (i = 0; i < tot; i++, ele_src++) {
341 if ((*ele_src)->head.htype & dst_elem_flag) {
350 else if (slot_dst->slot_type == BMO_OP_SLOT_MAPPING) {
351 GHashIterator gh_iter;
352 GHASH_ITER (gh_iter, slot_src->data.ghash) {
353 void *key = BLI_ghashIterator_getKey(&gh_iter);
354 void *val = BLI_ghashIterator_getValue(&gh_iter);
355 BLI_ghash_insert(slot_dst->data.ghash, key, val);
359 slot_dst->data = slot_src->data;
364 * BMESH OPSTACK SET XXX
366 * Sets the value of a slot depending on it's type
369 void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float f)
371 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
372 BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
373 if (!(slot->slot_type == BMO_OP_SLOT_FLT))
379 void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i)
381 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
382 BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
383 if (!(slot->slot_type == BMO_OP_SLOT_INT))
389 void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i)
391 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
392 BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
393 if (!(slot->slot_type == BMO_OP_SLOT_BOOL))
399 /* only supports square mats */
400 void BMO_slot_mat_set(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float *mat, int size)
402 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
403 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
404 if (!(slot->slot_type == BMO_OP_SLOT_MAT))
408 slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
411 copy_m4_m4(slot->data.p, (float (*)[4])mat);
413 else if (size == 3) {
414 copy_m4_m3(slot->data.p, (float (*)[3])mat);
417 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
419 zero_m4(slot->data.p);
423 void BMO_slot_mat4_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_mat[4][4])
425 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
426 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
427 if (!(slot->slot_type == BMO_OP_SLOT_MAT))
431 copy_m4_m4(r_mat, BMO_SLOT_AS_MATRIX(slot));
438 void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_mat[3][3])
440 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
441 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
442 if (!(slot->slot_type == BMO_OP_SLOT_MAT))
446 copy_m3_m4(r_mat, BMO_SLOT_AS_MATRIX(slot));
453 void BMO_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, void *p)
455 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
456 BLI_assert(slot->slot_type == BMO_OP_SLOT_PTR);
457 if (!(slot->slot_type == BMO_OP_SLOT_PTR))
463 void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float vec[3])
465 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
466 BLI_assert(slot->slot_type == BMO_OP_SLOT_VEC);
467 if (!(slot->slot_type == BMO_OP_SLOT_VEC))
470 copy_v3_v3(slot->data.vec, vec);
474 float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
476 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
477 BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
478 if (!(slot->slot_type == BMO_OP_SLOT_FLT))
484 int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
486 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
487 BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
488 if (!(slot->slot_type == BMO_OP_SLOT_INT))
494 bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
496 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
497 BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
498 if (!(slot->slot_type == BMO_OP_SLOT_BOOL))
504 /* if you want a copy of the elem buffer */
505 void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len)
507 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
510 /* could add support for mapping type */
511 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
513 ret = MEM_mallocN(sizeof(void *) * slot->len, __func__);
514 memcpy(ret, slot->data.buf, sizeof(void *) * slot->len);
519 void *BMO_slot_ptr_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
521 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
522 BLI_assert(slot->slot_type == BMO_OP_SLOT_PTR);
523 if (!(slot->slot_type == BMO_OP_SLOT_PTR))
529 void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3])
531 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
532 BLI_assert(slot->slot_type == BMO_OP_SLOT_VEC);
533 if (!(slot->slot_type == BMO_OP_SLOT_VEC))
536 copy_v3_v3(r_vec, slot->data.vec);
542 * Counts the number of elements of a certain type that have a
543 * specific flag enabled (or disabled if test_for_enabled is false).
547 static int bmo_mesh_flag_count(
548 BMesh *bm, const char htype, const short oflag,
549 const bool test_for_enabled)
551 int count_vert = 0, count_edge = 0, count_face = 0;
553 if (htype & BM_VERT) {
556 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
557 if (BMO_vert_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
562 if (htype & BM_EDGE) {
565 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
566 if (BMO_edge_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
571 if (htype & BM_FACE) {
574 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
575 if (BMO_face_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
581 return (count_vert + count_edge + count_face);
585 int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag)
587 return bmo_mesh_flag_count(bm, htype, oflag, true);
590 int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag)
592 return bmo_mesh_flag_count(bm, htype, oflag, false);
595 void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
597 if (htype & BM_VERT) {
600 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
601 BMO_vert_flag_disable(bm, ele, oflag);
604 if (htype & BM_EDGE) {
607 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
608 BMO_edge_flag_disable(bm, ele, oflag);
611 if (htype & BM_FACE) {
614 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
615 BMO_face_flag_disable(bm, ele, oflag);
620 void BMO_mesh_selected_remap(
622 BMOpSlot *slot_vert_map,
623 BMOpSlot *slot_edge_map,
624 BMOpSlot *slot_face_map,
625 const bool check_select)
627 if (bm->selected.first) {
628 BMEditSelection *ese, *ese_next;
629 BMOpSlot *slot_elem_map;
631 for (ese = bm->selected.first; ese; ese = ese_next) {
632 ese_next = ese->next;
634 switch (ese->htype) {
635 case BM_VERT: slot_elem_map = slot_vert_map; break;
636 case BM_EDGE: slot_elem_map = slot_edge_map; break;
637 default: slot_elem_map = slot_face_map; break;
640 ese->ele = BMO_slot_map_elem_get(slot_elem_map, ese->ele);
642 if (UNLIKELY((ese->ele == NULL) ||
643 (check_select && (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT) == false))))
645 BLI_remlink(&bm->selected, ese);
652 BMFace *f = BMO_slot_map_elem_get(slot_face_map, bm->act_face);
660 int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
662 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
663 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
665 /* check if its actually a buffer */
666 if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
672 int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
674 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
675 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
676 return BLI_ghash_len(slot->data.ghash);
679 /* inserts a key/value mapping into a mapping slot. note that it copies the
680 * value, it doesn't store a reference to it. */
682 void BMO_slot_map_insert(
683 BMOperator *op, BMOpSlot *slot,
684 const void *element, const void *data)
686 (void) op; /* Ignored in release builds. */
688 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
689 BMO_ASSERT_SLOT_IN_OP(slot, op);
691 BLI_ghash_insert(slot->data.ghash, (void *)element, (void *)data);
695 void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slot_code, int totadd)
697 BMOpSlot *slot = &op->slots[slot_code];
701 BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
703 /* check if its actually a buffer */
704 if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
707 if (slot->flag & BMOS_DYNAMIC_ARRAY) {
708 if (slot->len >= slot->size) {
709 slot->size = (slot->size + 1 + totadd) * 2;
711 allocsize = BMO_OPSLOT_TYPEINFO[bmo_opdefines[op->type]->slot_types[slot_code].type] * slot->size;
713 tmp = slot->data.buf;
714 slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
715 memcpy(slot->data.buf, tmp, allocsize);
722 slot->flag |= BMOS_DYNAMIC_ARRAY;
724 slot->size = slot->len + 2;
726 allocsize = BMO_OPSLOT_TYPEINFO[bmo_opdefines[op->type]->slot_types[slot_code].type] * slot->len;
728 tmp = slot->data.buf;
729 slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
730 memcpy(slot->data.buf, tmp, allocsize);
733 return slot->data.buf;
737 void BMO_slot_map_to_flag(
738 BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
739 const char htype, const short oflag)
741 GHashIterator gh_iter;
742 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
745 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
748 GHASH_ITER (gh_iter, slot->data.ghash) {
749 ele_f = BLI_ghashIterator_getKey(&gh_iter);
750 if (ele_f->head.htype & htype) {
751 BMO_elem_flag_enable(bm, ele_f, oflag);
756 void *BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int len)
758 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
760 /* check if its actually a buffer */
761 if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
766 slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slot_type] * len);
769 slot->data.buf = NULL;
772 return slot->data.buf;
776 * \brief BMO_ALL_TO_SLOT
778 * Copies all elements of a certain type into an operator slot.
780 void BMO_slot_buffer_from_all(
781 BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
782 const char *slot_name, const char htype)
784 BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
785 int totelement = 0, i = 0;
787 BLI_assert(output->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
788 BLI_assert(((output->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
790 if (htype & BM_VERT) totelement += bm->totvert;
791 if (htype & BM_EDGE) totelement += bm->totedge;
792 if (htype & BM_FACE) totelement += bm->totface;
798 BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
800 /* TODO - collapse these loops into one */
802 if (htype & BM_VERT) {
803 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
804 output->data.buf[i] = ele;
809 if (htype & BM_EDGE) {
810 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
811 output->data.buf[i] = ele;
816 if (htype & BM_FACE) {
817 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
818 output->data.buf[i] = ele;
826 * \brief BMO_HEADERFLAG_TO_SLOT
828 * Copies elements of a certain type, which have a certain header flag
829 * enabled/disabled into a slot for an operator.
831 static void bmo_slot_buffer_from_hflag(
832 BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
833 const char htype, const char hflag,
834 const bool test_for_enabled)
836 BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
837 int totelement = 0, i = 0;
838 const bool respecthide = ((op->flag & BMO_FLAG_RESPECT_HIDE) != 0) && ((hflag & BM_ELEM_HIDDEN) == 0);
840 BLI_assert(output->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
841 BLI_assert(((output->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
842 BLI_assert((output->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0);
844 if (test_for_enabled)
845 totelement = BM_mesh_elem_hflag_count_enabled(bm, htype, hflag, respecthide);
847 totelement = BM_mesh_elem_hflag_count_disabled(bm, htype, hflag, respecthide);
853 BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
855 /* TODO - collapse these loops into one */
857 if (htype & BM_VERT) {
858 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
859 if ((!respecthide || !BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) &&
860 BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
862 output->data.buf[i] = ele;
868 if (htype & BM_EDGE) {
869 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
870 if ((!respecthide || !BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) &&
871 BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
873 output->data.buf[i] = ele;
879 if (htype & BM_FACE) {
880 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
881 if ((!respecthide || !BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) &&
882 BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
884 output->data.buf[i] = ele;
895 void BMO_slot_buffer_from_enabled_hflag(
896 BMesh *bm, BMOperator *op,
897 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
898 const char htype, const char hflag)
900 bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, true);
903 void BMO_slot_buffer_from_disabled_hflag(
904 BMesh *bm, BMOperator *op,
905 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
906 const char htype, const char hflag)
908 bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, false);
911 void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele)
913 BMO_ASSERT_SLOT_IN_OP(slot, op);
914 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
915 BLI_assert(slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE);
916 BLI_assert(slot->len == 0 || slot->len == 1);
918 BLI_assert(slot->slot_subtype.elem & ele->htype);
920 slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4); /* XXX, why 'x4' ? */
922 *slot->data.buf = ele;
925 void BMO_slot_buffer_from_array(BMOperator *op, BMOpSlot *slot, BMHeader **ele_buffer, int ele_buffer_len)
927 BMO_ASSERT_SLOT_IN_OP(slot, op);
928 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
929 BLI_assert(slot->len == 0 || slot->len == ele_buffer_len);
931 if (slot->data.buf == NULL) {
932 slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(*slot->data.buf) * ele_buffer_len);
935 slot->len = ele_buffer_len;
936 memcpy(slot->data.buf, ele_buffer, ele_buffer_len * sizeof(*slot->data.buf));
940 void *BMO_slot_buffer_get_single(BMOpSlot *slot)
942 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
943 BLI_assert(slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE);
944 BLI_assert(slot->len == 0 || slot->len == 1);
946 return slot->len ? (BMHeader *)slot->data.buf[0] : NULL;
950 * Copies the values from another slot to the end of the output slot.
952 void _bmo_slot_buffer_append(
953 BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
954 BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
955 struct MemArena *arena_dst)
957 BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
958 BMOpSlot *slot_src = BMO_slot_get(slot_args_src, slot_name_src);
960 BLI_assert(slot_dst->slot_type == BMO_OP_SLOT_ELEMENT_BUF &&
961 slot_src->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
963 if (slot_dst->len == 0) {
964 /* output slot is empty, copy rather than append */
965 _bmo_slot_copy(slot_args_src, slot_name_src,
966 slot_args_dst, slot_name_dst,
969 else if (slot_src->len != 0) {
970 int elem_size = BMO_OPSLOT_TYPEINFO[slot_dst->slot_type];
971 int alloc_size = elem_size * (slot_dst->len + slot_src->len);
972 /* allocate new buffer */
973 void *buf = BLI_memarena_alloc(arena_dst, alloc_size);
976 memcpy(buf, slot_dst->data.buf, elem_size * slot_dst->len);
977 memcpy(((char *)buf) + elem_size * slot_dst->len, slot_src->data.buf, elem_size * slot_src->len);
979 slot_dst->data.buf = buf;
980 slot_dst->len += slot_src->len;
985 * \brief BMO_FLAG_TO_SLOT
987 * Copies elements of a certain type, which have a certain flag set
988 * into an output slot for an operator.
990 static void bmo_slot_buffer_from_flag(
991 BMesh *bm, BMOperator *op,
992 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
993 const char htype, const short oflag,
994 const bool test_for_enabled)
996 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
997 int totelement, i = 0;
999 BLI_assert(op->slots_in == slot_args || op->slots_out == slot_args);
1001 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1002 BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1003 BLI_assert((slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0);
1005 if (test_for_enabled)
1006 totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag);
1008 totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag);
1013 BMHeader **ele_array;
1015 BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
1017 ele_array = (BMHeader **)slot->data.buf;
1019 /* TODO - collapse these loops into one */
1021 if (htype & BM_VERT) {
1022 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
1023 if (BMO_vert_flag_test_bool(bm, (BMVert *)ele, oflag) == test_for_enabled) {
1030 if (htype & BM_EDGE) {
1031 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
1032 if (BMO_edge_flag_test_bool(bm, (BMEdge *)ele, oflag) == test_for_enabled) {
1039 if (htype & BM_FACE) {
1040 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
1041 if (BMO_face_flag_test_bool(bm, (BMFace *)ele, oflag) == test_for_enabled) {
1053 void BMO_slot_buffer_from_enabled_flag(
1054 BMesh *bm, BMOperator *op,
1055 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1056 const char htype, const short oflag)
1058 bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, true);
1061 void BMO_slot_buffer_from_disabled_flag(
1062 BMesh *bm, BMOperator *op,
1063 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1064 const char htype, const short oflag)
1066 bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, false);
1070 * \brief BMO_FLAG_BUFFER
1072 * Header Flags elements in a slots buffer, automatically
1073 * using the selection API where appropriate.
1075 void BMO_slot_buffer_hflag_enable(
1077 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1078 const char htype, const char hflag, const bool do_flush)
1080 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1081 BMElem **data = (BMElem **)slot->data.buf;
1083 const bool do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
1084 const bool do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
1086 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1087 BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1088 BLI_assert((slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0);
1090 for (i = 0; i < slot->len; i++, data++) {
1091 if (!(htype & (*data)->head.htype))
1094 if (do_flush_select) {
1095 BM_elem_select_set(bm, *data, true);
1098 if (do_flush_hide) {
1099 BM_elem_hide_set(bm, *data, false);
1102 BM_elem_flag_enable(*data, hflag);
1107 * \brief BMO_FLAG_BUFFER
1109 * Removes flags from elements in a slots buffer, automatically
1110 * using the selection API where appropriate.
1112 void BMO_slot_buffer_hflag_disable(
1114 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1115 const char htype, const char hflag, const bool do_flush)
1117 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1118 BMElem **data = (BMElem **)slot->data.buf;
1120 const bool do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
1121 const bool do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
1123 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1124 BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1126 for (i = 0; i < slot->len; i++, data++) {
1127 if (!(htype & (*data)->head.htype))
1130 if (do_flush_select) {
1131 BM_elem_select_set(bm, *data, false);
1134 if (do_flush_hide) {
1135 BM_elem_hide_set(bm, *data, false);
1138 BM_elem_flag_disable(*data, hflag);
1143 * \brief BMO_FLAG_BUFFER
1145 * Flags elements in a slots buffer
1147 void BMO_slot_buffer_flag_enable(
1149 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1150 const char htype, const short oflag)
1152 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1153 BMHeader **data = slot->data.p;
1156 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1157 BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1159 for (i = 0; i < slot->len; i++) {
1160 if (!(htype & data[i]->htype))
1163 BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
1168 * \brief BMO_FLAG_BUFFER
1170 * Removes flags from elements in a slots buffer
1172 void BMO_slot_buffer_flag_disable(
1174 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1175 const char htype, const short oflag)
1177 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1178 BMHeader **data = (BMHeader **)slot->data.buf;
1181 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1182 BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1184 for (i = 0; i < slot->len; i++) {
1185 if (!(htype & data[i]->htype))
1188 BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
1194 * \brief ALLOC/FREE FLAG LAYER
1196 * Used by operator stack to free/allocate
1197 * private flag data. This is allocated
1198 * using a mempool so the allocation/frees
1199 * should be quite fast.
1202 * Investigate not freeing flag layers until
1203 * all operators have been executed. This would
1204 * save a lot of realloc potentially.
1206 static void bmo_flag_layer_alloc(BMesh *bm)
1208 /* set the index values since we are looping over all data anyway,
1209 * may save time later on */
1211 BLI_mempool *voldpool = bm->vtoolflagpool; /* old flag pool */
1212 BLI_mempool *eoldpool = bm->etoolflagpool; /* old flag pool */
1213 BLI_mempool *foldpool = bm->ftoolflagpool; /* old flag pool */
1215 /* store memcpy size for reuse */
1216 const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
1220 bm->vtoolflagpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, bm->totvert, 512, BLI_MEMPOOL_NOP);
1221 bm->etoolflagpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, bm->totedge, 512, BLI_MEMPOOL_NOP);
1222 bm->ftoolflagpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, bm->totface, 512, BLI_MEMPOOL_NOP);
1224 /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
1228 BMVert_OFlag *v_oflag;
1229 BLI_mempool *newpool = bm->vtoolflagpool;
1230 BM_ITER_MESH_INDEX (v_oflag, &iter, bm, BM_VERTS_OF_MESH, i) {
1231 void *oldflags = v_oflag->oflags;
1232 v_oflag->oflags = BLI_mempool_calloc(newpool);
1233 memcpy(v_oflag->oflags, oldflags, old_totflags_size);
1234 BM_elem_index_set(&v_oflag->base, i); /* set_inline */
1235 BM_ELEM_API_FLAG_CLEAR((BMElemF *)v_oflag);
1238 BMEdge_OFlag *e_oflag;
1239 newpool = bm->etoolflagpool;
1240 BM_ITER_MESH_INDEX (e_oflag, &iter, bm, BM_EDGES_OF_MESH, i) {
1241 void *oldflags = e_oflag->oflags;
1242 e_oflag->oflags = BLI_mempool_calloc(newpool);
1243 memcpy(e_oflag->oflags, oldflags, old_totflags_size);
1244 BM_elem_index_set(&e_oflag->base, i); /* set_inline */
1245 BM_ELEM_API_FLAG_CLEAR((BMElemF *)e_oflag);
1248 BMFace_OFlag *f_oflag;
1249 newpool = bm->ftoolflagpool;
1250 BM_ITER_MESH_INDEX (f_oflag, &iter, bm, BM_FACES_OF_MESH, i) {
1251 void *oldflags = f_oflag->oflags;
1252 f_oflag->oflags = BLI_mempool_calloc(newpool);
1253 memcpy(f_oflag->oflags, oldflags, old_totflags_size);
1254 BM_elem_index_set(&f_oflag->base, i); /* set_inline */
1255 BM_ELEM_API_FLAG_CLEAR((BMElemF *)f_oflag);
1258 BLI_mempool_destroy(voldpool);
1259 BLI_mempool_destroy(eoldpool);
1260 BLI_mempool_destroy(foldpool);
1262 bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1265 static void bmo_flag_layer_free(BMesh *bm)
1267 /* set the index values since we are looping over all data anyway,
1268 * may save time later on */
1270 BLI_mempool *voldpool = bm->vtoolflagpool;
1271 BLI_mempool *eoldpool = bm->etoolflagpool;
1272 BLI_mempool *foldpool = bm->ftoolflagpool;
1274 /* store memcpy size for reuse */
1275 const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
1277 /* de-increment the totflags first.. */
1280 bm->vtoolflagpool = BLI_mempool_create(new_totflags_size, bm->totvert, 512, BLI_MEMPOOL_NOP);
1281 bm->etoolflagpool = BLI_mempool_create(new_totflags_size, bm->totedge, 512, BLI_MEMPOOL_NOP);
1282 bm->ftoolflagpool = BLI_mempool_create(new_totflags_size, bm->totface, 512, BLI_MEMPOOL_NOP);
1284 /* now go through and memcpy all the flag */
1288 BMVert_OFlag *v_oflag;
1289 BLI_mempool *newpool = bm->vtoolflagpool;
1290 BM_ITER_MESH_INDEX (v_oflag, &iter, bm, BM_VERTS_OF_MESH, i) {
1291 void *oldflags = v_oflag->oflags;
1292 v_oflag->oflags = BLI_mempool_alloc(newpool);
1293 memcpy(v_oflag->oflags, oldflags, new_totflags_size);
1294 BM_elem_index_set(&v_oflag->base, i); /* set_inline */
1295 BM_ELEM_API_FLAG_CLEAR((BMElemF *)v_oflag);
1298 BMEdge_OFlag *e_oflag;
1299 newpool = bm->etoolflagpool;
1300 BM_ITER_MESH_INDEX (e_oflag, &iter, bm, BM_EDGES_OF_MESH, i) {
1301 void *oldflags = e_oflag->oflags;
1302 e_oflag->oflags = BLI_mempool_alloc(newpool);
1303 memcpy(e_oflag->oflags, oldflags, new_totflags_size);
1304 BM_elem_index_set(&e_oflag->base, i); /* set_inline */
1305 BM_ELEM_API_FLAG_CLEAR((BMElemF *)e_oflag);
1308 BMFace_OFlag *f_oflag;
1309 newpool = bm->ftoolflagpool;
1310 BM_ITER_MESH_INDEX (f_oflag, &iter, bm, BM_FACES_OF_MESH, i) {
1311 void *oldflags = f_oflag->oflags;
1312 f_oflag->oflags = BLI_mempool_alloc(newpool);
1313 memcpy(f_oflag->oflags, oldflags, new_totflags_size);
1314 BM_elem_index_set(&f_oflag->base, i); /* set_inline */
1315 BM_ELEM_API_FLAG_CLEAR((BMElemF *)f_oflag);
1318 BLI_mempool_destroy(voldpool);
1319 BLI_mempool_destroy(eoldpool);
1320 BLI_mempool_destroy(foldpool);
1322 bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1325 static void bmo_flag_layer_clear(BMesh *bm)
1327 /* set the index values since we are looping over all data anyway,
1328 * may save time later on */
1329 const BMFlagLayer zero_flag = {0};
1331 const int totflags_offset = bm->totflags - 1;
1333 /* now go through and memcpy all the flag */
1338 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1339 ele->oflags[totflags_offset] = zero_flag;
1340 BM_elem_index_set(&ele->base, i); /* set_inline */
1347 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1348 ele->oflags[totflags_offset] = zero_flag;
1349 BM_elem_index_set(&ele->base, i); /* set_inline */
1356 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1357 ele->oflags[totflags_offset] = zero_flag;
1358 BM_elem_index_set(&ele->base, i); /* set_inline */
1362 bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1365 void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
1367 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1369 if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
1372 return slot->data.buf ? *slot->data.buf : NULL;
1376 * \brief New Iterator
1378 * \param restrictmask restricts the iteration to certain element types
1379 * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
1380 * over an element buffer (not a mapping). */
1383 BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
1384 const char restrictmask)
1386 BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1388 memset(iter, 0, sizeof(BMOIter));
1392 iter->restrictmask = restrictmask;
1394 if (iter->slot->slot_type == BMO_OP_SLOT_MAPPING) {
1395 BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1397 else if (iter->slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
1398 BLI_assert(restrictmask & slot->slot_subtype.elem);
1404 return BMO_iter_step(iter);
1407 void *BMO_iter_step(BMOIter *iter)
1409 BMOpSlot *slot = iter->slot;
1410 if (slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
1413 if (iter->cur >= slot->len) {
1417 ele = slot->data.buf[iter->cur++];
1418 while (!(iter->restrictmask & ele->htype)) {
1419 if (iter->cur >= slot->len) {
1423 ele = slot->data.buf[iter->cur++];
1424 BLI_assert((ele == NULL) || (slot->slot_subtype.elem & ele->htype));
1427 BLI_assert((ele == NULL) || (slot->slot_subtype.elem & ele->htype));
1431 else if (slot->slot_type == BMO_OP_SLOT_MAPPING) {
1435 if (BLI_ghashIterator_done(&iter->giter) == false) {
1436 ret = BLI_ghashIterator_getKey(&iter->giter);
1437 iter->val = BLI_ghashIterator_getValue_p(&iter->giter);
1439 BLI_ghashIterator_step(&iter->giter);
1455 /* used for iterating over mappings */
1458 * Returns a pointer to the key-value when iterating over mappings.
1459 * remember for pointer maps this will be a pointer to a pointer.
1461 void **BMO_iter_map_value_p(BMOIter *iter)
1466 void *BMO_iter_map_value_ptr(BMOIter *iter)
1468 BLI_assert(ELEM(iter->slot->slot_subtype.map,
1469 BMO_OP_SLOT_SUBTYPE_MAP_ELEM, BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL));
1470 return iter->val ? *iter->val : NULL;
1474 float BMO_iter_map_value_float(BMOIter *iter)
1476 BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_FLT);
1477 return **((float **)iter->val);
1480 int BMO_iter_map_value_int(BMOIter *iter)
1482 BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INT);
1483 return **((int **)iter->val);
1486 bool BMO_iter_map_value_bool(BMOIter *iter)
1488 BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_BOOL);
1489 return **((bool **)iter->val);
1493 typedef struct BMOpError {
1494 struct BMOpError *next, *prev;
1500 void BMO_error_clear(BMesh *bm)
1502 while (BMO_error_pop(bm, NULL, NULL));
1505 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1507 BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1509 err->errorcode = errcode;
1511 msg = bmo_error_messages[errcode];
1516 BLI_addhead(&bm->errorstack, err);
1519 bool BMO_error_occurred(BMesh *bm)
1521 return (BLI_listbase_is_empty(&bm->errorstack) == false);
1524 /* returns error code or 0 if no error */
1525 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1527 BMOpError *err = bm->errorstack.first;
1532 if (msg) *msg = err->msg;
1533 if (op) *op = err->op;
1535 return err->errorcode;
1538 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1540 int errorcode = BMO_error_get(bm, msg, op);
1543 BMOpError *err = bm->errorstack.first;
1545 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1553 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1555 static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
1559 while (slot_args->slot_name) {
1560 if (STREQLEN(identifier, slot_args->slot_name, MAX_SLOTNAME)) {
1570 static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
1572 int i = bmo_name_to_slotcode(slot_args, identifier);
1574 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, identifier);
1580 int BMO_opcode_from_opname(const char *opname)
1583 const uint tot = bmo_opdefines_total;
1585 for (i = 0; i < tot; i++) {
1586 if (STREQ(bmo_opdefines[i]->opname, opname)) {
1593 static int BMO_opcode_from_opname_check(const char *opname)
1595 int i = BMO_opcode_from_opname(opname);
1597 fprintf(stderr, "%s: could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1602 * \brief Format Strings for #BMOperator Initialization.
1604 * This system is used to execute or initialize an operator,
1605 * using a formatted-string system.
1607 * The basic format for the format string is:
1608 * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
1613 * BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
1614 * "delete context=%i geom=%hv",
1615 * DEL_ONLYFACES, BM_ELEM_SELECT);
1619 * **Primitive Types**
1620 * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
1621 * - `i` - int. #BMO_OP_SLOT_INT
1622 * - `f` - float. #BMO_OP_SLOT_FLT
1623 * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
1624 * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
1625 * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
1626 * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
1631 * Pass an existing slot which is copied to either an input or output slot.
1632 * Taking the operator and slot-name pair of args (BMOperator *, const char *).
1633 * - `s` - slot_in (lower case)
1634 * - `S` - slot_out (upper case)
1637 * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
1638 * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
1639 * - `eb` - elem buffer, take an array and a length.
1640 * - `av` - all verts
1641 * - `ae` - all edges
1642 * - `af` - all faces
1643 * - `hv` - header flagged verts (hflag)
1644 * - `he` - header flagged edges (hflag)
1645 * - `hf` - header flagged faces (hflag)
1646 * - `Hv` - header flagged verts (hflag off)
1647 * - `He` - header flagged edges (hflag off)
1648 * - `Hf` - header flagged faces (hflag off)
1649 * - `fv` - flagged verts (oflag)
1650 * - `fe` - flagged edges (oflag)
1651 * - `ff` - flagged faces (oflag)
1652 * - `Fv` - flagged verts (oflag off)
1653 * - `Fe` - flagged edges (oflag off)
1654 * - `Ff` - flagged faces (oflag off)
1656 * \note The common v/e/f suffix can be mixed,
1657 * so `avef` is can be used for all verts, edges and faces.
1658 * Order is not important so `Hfev` is also valid (all unflagged verts, edges and faces).
1661 bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, va_list vlist)
1664 char *opname, *ofmt, *fmt;
1665 char slot_name[64] = {0};
1670 /* basic useful info to help find where bmop formatting strings fail */
1671 const char *err_reason = "Unknown";
1674 #define GOTO_ERROR(reason) \
1676 err_reason = reason; \
1677 lineno = __LINE__; \
1681 /* we muck around in here, so dup it */
1682 fmt = ofmt = BLI_strdup(_fmt);
1684 /* find operator name */
1685 i = strcspn(fmt, " ");
1688 noslot = (opname[i] == '\0');
1691 fmt += i + (noslot ? 0 : 1);
1693 i = BMO_opcode_from_opname_check(opname);
1701 BMO_op_init(bm, op, flag, opname);
1702 // def = bmo_opdefines[i];
1705 state = true; /* false: not inside slot_code name, true: inside slot_code name */
1709 /* jump past leading whitespace */
1710 i = strspn(fmt, " ");
1713 /* ignore trailing whitespace */
1717 /* find end of slot name, only "slot=%f", can be used */
1718 i = strcspn(fmt, "=");
1720 GOTO_ERROR("could not match end of slot name");
1725 if (bmo_name_to_slotcode_check(op->slots_in, fmt) < 0) {
1726 GOTO_ERROR("name to slot code check failed");
1729 BLI_strncpy(slot_name, fmt, sizeof(slot_name));
1743 const char c = NEXT_CHAR(fmt);
1746 if (c == '3') size = 3;
1747 else if (c == '4') size = 4;
1748 else GOTO_ERROR("matrix size was not 3 or 4");
1750 BMO_slot_mat_set(op, op->slots_in, slot_name, va_arg(vlist, void *), size);
1756 BMO_slot_vec_set(op->slots_in, slot_name, va_arg(vlist, float *));
1762 BMOpSlot *slot = BMO_slot_get(op->slots_in, slot_name);
1764 if (NEXT_CHAR(fmt) == 'b') {
1765 BMHeader **ele_buffer = va_arg(vlist, void *);
1766 int ele_buffer_len = va_arg(vlist, int);
1768 BMO_slot_buffer_from_array(op, slot, ele_buffer, ele_buffer_len);
1772 /* single vert/edge/face */
1773 BMHeader *ele = va_arg(vlist, void *);
1775 BMO_slot_buffer_from_single(op, slot, ele);
1784 BMOperator *op_other = va_arg(vlist, void *);
1785 const char *slot_name_other = va_arg(vlist, char *);
1788 BLI_assert(bmo_name_to_slotcode_check(op_other->slots_in, slot_name_other) != -1);
1789 BMO_slot_copy(op_other, slots_in, slot_name_other,
1790 op, slots_in, slot_name);
1793 BLI_assert(bmo_name_to_slotcode_check(op_other->slots_out, slot_name_other) != -1);
1794 BMO_slot_copy(op_other, slots_out, slot_name_other,
1795 op, slots_in, slot_name);
1801 BMO_slot_int_set(op->slots_in, slot_name, va_arg(vlist, int));
1805 BMO_slot_bool_set(op->slots_in, slot_name, va_arg(vlist, int));
1809 BMO_slot_ptr_set(op->slots_in, slot_name, va_arg(vlist, void *));
1819 if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\0') {
1820 BMO_slot_float_set(op->slots_in, slot_name, va_arg(vlist, double));
1827 const char c = NEXT_CHAR(fmt);
1828 if (c == 'f') htype_set = BM_FACE;
1829 else if (c == 'e') htype_set = BM_EDGE;
1830 else if (c == 'v') htype_set = BM_VERT;
1835 if (UNLIKELY(htype & htype_set)) {
1836 GOTO_ERROR("htype duplicated");
1844 BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1846 else if (type == 'H') {
1847 BMO_slot_buffer_from_disabled_hflag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1849 else if (type == 'a') {
1850 BMO_slot_buffer_from_all(bm, op, op->slots_in, slot_name, htype);
1852 else if (type == 'f') {
1853 BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1855 else if (type == 'F') {
1856 BMO_slot_buffer_from_disabled_flag(bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1864 "%s: unrecognized bmop format char: '%c', %d in '%s'\n",
1865 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1876 /* non urgent todo - explain exactly what is failing */
1877 fprintf(stderr, "%s: error parsing formatting string\n", __func__);
1879 fprintf(stderr, "string: '%s', position %d\n", _fmt, (int)(fmt - ofmt));
1880 fprintf(stderr, " ");
1882 int pos = (int)(fmt - ofmt);
1883 for (i = 0; i < pos; i++) {
1884 fprintf(stderr, " ");
1886 fprintf(stderr, "^\n");
1889 fprintf(stderr, "source code: %s:%d\n", __FILE__, lineno);
1891 fprintf(stderr, "reason: %s\n", err_reason);
1896 BMO_op_finish(bm, op);
1904 bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, ...)
1908 va_start(list, fmt);
1909 if (!BMO_op_vinitf(bm, op, flag, fmt, list)) {
1910 printf("%s: failed\n", __func__);
1919 bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt, ...)
1924 va_start(list, fmt);
1925 if (!BMO_op_vinitf(bm, &op, flag, fmt, list)) {
1926 printf("%s: failed, format is:\n \"%s\"\n", __func__, fmt);
1931 BMO_op_exec(bm, &op);
1932 BMO_op_finish(bm, &op);