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 "intern/bmesh_private.h"
42 /* forward declarations */
43 static void bmo_flag_layer_alloc(BMesh *bm);
44 static void bmo_flag_layer_free(BMesh *bm);
45 static void bmo_flag_layer_clear(BMesh *bm);
46 static int bmo_name_to_slotcode(BMOpDefine *def, const char *name);
47 static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name);
48 static int bmo_opname_to_opcode(const char *opname);
50 static const char *bmo_error_messages[] = {
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",
59 "Can not deal with non-manifold geometry",
61 "Internal mesh error",
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(BMOElemMapping) /* 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))
102 /* add flag layer, if appropriate */
103 if (bm->stackdepth > 1)
104 bmo_flag_layer_alloc(bm);
106 bmo_flag_layer_clear(bm);
110 * \brief BMESH OPSTACK POP
112 * Pops the opstack one level and frees a flag layer if appropriate
114 * BMESH_TODO: investigate NOT freeing flag layers.
116 void BMO_pop(BMesh *bm)
118 if (bm->stackdepth > 1)
119 bmo_flag_layer_free(bm);
125 * \brief BMESH OPSTACK INIT OP
127 * Initializes an operator structure to a certain type
129 void BMO_op_init(BMesh *bm, BMOperator *op, const char *opname)
131 int i, opcode = bmo_opname_to_opcode(opname);
134 BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
140 opcode = 0; /* error!, already printed, have a better way to handle this? */
143 memset(op, 0, sizeof(BMOperator));
145 op->flag = opdefines[opcode]->flag;
147 /* initialize the operator slot types */
148 for (i = 0; opdefines[opcode]->slot_types[i].type; i++) {
149 op->slot_args[i].slot_type = opdefines[opcode]->slot_types[i].type;
150 op->slot_args[i].index = i;
154 op->exec = opdefines[opcode]->exec;
156 /* memarena, used for operator's slot buffers */
157 op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
158 BLI_memarena_use_calloc(op->arena);
162 * \brief BMESH OPSTACK EXEC OP
164 * Executes a passed in operator.
166 * This handles the allocation and freeing of temporary flag
167 * layers and starting/stopping the modeling loop.
168 * Can be called from other operators exec callbacks as well.
170 void BMO_op_exec(BMesh *bm, BMOperator *op)
175 if (bm->stackdepth == 2)
176 bmesh_edit_begin(bm, op->flag);
179 if (bm->stackdepth == 2)
180 bmesh_edit_end(bm, op->flag);
186 * \brief BMESH OPSTACK FINISH OP
188 * Does housekeeping chores related to finishing up an operator.
190 void BMO_op_finish(BMesh *bm, BMOperator *op)
195 for (i = 0; opdefines[op->type]->slot_types[i].type; i++) {
196 slot = &op->slot_args[i];
197 if (slot->slot_type == BMO_OP_SLOT_MAPPING) {
198 if (slot->data.ghash)
199 BLI_ghash_free(slot->data.ghash, NULL, NULL);
203 BLI_memarena_free(op->arena);
206 BM_ELEM_INDEX_VALIDATE(bm, "post bmo", opdefines[op->type]->name);
213 * \brief BMESH OPSTACK HAS SLOT
215 * \return Success if the slot if found.
217 int BMO_slot_exists(BMOperator *op, const char *slot_name)
219 int slot_code = bmo_name_to_slotcode(opdefines[op->type], slot_name);
220 return (slot_code >= 0);
224 * \brief BMESH OPSTACK GET SLOT
226 * Returns a pointer to the slot of type 'slot_code'
228 BMOpSlot *BMO_slot_get(BMOperator *op, const char *slot_name)
230 int slot_code = bmo_name_to_slotcode_check(opdefines[op->type], slot_name);
233 return &BMOpEmptySlot;
236 return &(op->slot_args[slot_code]);
240 * \brief BMESH OPSTACK COPY SLOT
242 * Copies data from one slot to another.
244 void BMO_slot_copy(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
246 BMOpSlot *source_slot = BMO_slot_get(source_op, src);
247 BMOpSlot *dest_slot = BMO_slot_get(dest_op, dst);
249 if (source_slot == dest_slot)
252 if (source_slot->slot_type != dest_slot->slot_type) {
253 /* possibly assert here? */
257 if (dest_slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
259 dest_slot->data.buf = NULL;
260 dest_slot->len = source_slot->len;
261 if (dest_slot->len) {
262 const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[dest_slot->slot_type] * dest_slot->len;
263 dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
264 memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
267 else if (dest_slot->slot_type == BMO_OP_SLOT_MAPPING) {
269 BMOElemMapping *srcmap, *dstmap;
272 if (!source_slot->data.ghash) {
276 if (!dest_slot->data.ghash) {
277 dest_slot->data.ghash = BLI_ghash_ptr_new("bmesh operator 2");
280 BLI_ghashIterator_init(&it, source_slot->data.ghash);
281 for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
282 BLI_ghashIterator_step(&it))
284 dstmap = BLI_memarena_alloc(dest_op->arena, sizeof(*dstmap) + srcmap->len);
286 dstmap->element = srcmap->element;
287 dstmap->len = srcmap->len;
288 memcpy(dstmap + 1, srcmap + 1, srcmap->len);
290 BLI_ghash_insert(dest_slot->data.ghash, dstmap->element, dstmap);
294 dest_slot->data = source_slot->data;
299 * BMESH OPSTACK SET XXX
301 * Sets the value of a slot depending on it's type
304 void BMO_slot_float_set(BMOperator *op, const char *slot_name, const float f)
306 BMOpSlot *slot = BMO_slot_get(op, slot_name);
307 BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
308 if (!(slot->slot_type == BMO_OP_SLOT_FLT))
314 void BMO_slot_int_set(BMOperator *op, const char *slot_name, const int i)
316 BMOpSlot *slot = BMO_slot_get(op, slot_name);
317 BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
318 if (!(slot->slot_type == BMO_OP_SLOT_INT))
324 void BMO_slot_bool_set(BMOperator *op, const char *slot_name, const int i)
326 BMOpSlot *slot = BMO_slot_get(op, slot_name);
327 BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
328 if (!(slot->slot_type == BMO_OP_SLOT_BOOL))
334 /* only supports square mats */
335 void BMO_slot_mat_set(BMOperator *op, const char *slot_name, const float *mat, int size)
337 BMOpSlot *slot = BMO_slot_get(op, slot_name);
338 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
339 if (!(slot->slot_type == BMO_OP_SLOT_MAT))
343 slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
346 memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
348 else if (size == 3) {
349 copy_m4_m3(slot->data.p, (float (*)[3])mat);
352 fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
354 memset(slot->data.p, 0, sizeof(float) * 4 * 4);
358 void BMO_slot_mat4_get(BMOperator *op, const char *slot_name, float r_mat[4][4])
360 BMOpSlot *slot = BMO_slot_get(op, slot_name);
361 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
362 if (!(slot->slot_type == BMO_OP_SLOT_MAT))
365 copy_m4_m4(r_mat, (float (*)[4])slot->data.p);
368 void BMO_slot_mat3_set(BMOperator *op, const char *slot_name, float r_mat[3][3])
370 BMOpSlot *slot = BMO_slot_get(op, slot_name);
371 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
372 if (!(slot->slot_type == BMO_OP_SLOT_MAT))
375 copy_m3_m4(r_mat, slot->data.p);
378 void BMO_slot_ptr_set(BMOperator *op, const char *slot_name, void *p)
380 BMOpSlot *slot = BMO_slot_get(op, slot_name);
381 BLI_assert(slot->slot_type == BMO_OP_SLOT_PNT);
382 if (!(slot->slot_type == BMO_OP_SLOT_PNT))
388 void BMO_slot_vec_set(BMOperator *op, const char *slot_name, const float vec[3])
390 BMOpSlot *slot = BMO_slot_get(op, slot_name);
391 BLI_assert(slot->slot_type == BMO_OP_SLOT_VEC);
392 if (!(slot->slot_type == BMO_OP_SLOT_VEC))
395 copy_v3_v3(slot->data.vec, vec);
399 float BMO_slot_float_get(BMOperator *op, const char *slot_name)
401 BMOpSlot *slot = BMO_slot_get(op, slot_name);
402 BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
403 if (!(slot->slot_type == BMO_OP_SLOT_FLT))
409 int BMO_slot_int_get(BMOperator *op, const char *slot_name)
411 BMOpSlot *slot = BMO_slot_get(op, slot_name);
412 BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
413 if (!(slot->slot_type == BMO_OP_SLOT_INT))
419 int BMO_slot_bool_get(BMOperator *op, const char *slot_name)
421 BMOpSlot *slot = BMO_slot_get(op, slot_name);
422 BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
423 if (!(slot->slot_type == BMO_OP_SLOT_BOOL))
430 void *BMO_slot_ptr_get(BMOperator *op, const char *slot_name)
432 BMOpSlot *slot = BMO_slot_get(op, slot_name);
433 BLI_assert(slot->slot_type == BMO_OP_SLOT_PNT);
434 if (!(slot->slot_type == BMO_OP_SLOT_PNT))
440 void BMO_slot_vec_get(BMOperator *op, const char *slot_name, float r_vec[3])
442 BMOpSlot *slot = BMO_slot_get(op, slot_name);
443 BLI_assert(slot->slot_type == BMO_OP_SLOT_VEC);
444 if (!(slot->slot_type == BMO_OP_SLOT_VEC))
447 copy_v3_v3(r_vec, slot->data.vec);
453 * Counts the number of elements of a certain type that have a
454 * specific flag enabled (or disabled if test_for_enabled is false).
458 static int bmo_mesh_flag_count(BMesh *bm, const char htype, const short oflag,
459 const short test_for_enabled)
461 const char iter_types[3] = {BM_VERTS_OF_MESH,
465 const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
472 BLI_assert(ELEM(TRUE, FALSE, test_for_enabled));
474 for (i = 0; i < 3; i++) {
475 if (htype & flag_types[i]) {
476 BM_ITER_MESH (ele_f, &iter, bm, iter_types[i]) {
477 if (BMO_elem_flag_test_bool(bm, ele_f, oflag) == test_for_enabled)
487 int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag)
489 return bmo_mesh_flag_count(bm, htype, oflag, TRUE);
492 int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag)
494 return bmo_mesh_flag_count(bm, htype, oflag, FALSE);
497 void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
499 const char iter_types[3] = {BM_VERTS_OF_MESH,
503 const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
509 for (i = 0; i < 3; i++) {
510 if (htype & flag_types[i]) {
511 BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
512 BMO_elem_flag_disable(bm, ele, oflag);
518 int BMO_slot_buffer_count(BMesh *UNUSED(bm), BMOperator *op, const char *slot_name)
520 BMOpSlot *slot = BMO_slot_get(op, slot_name);
521 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
523 /* check if its actually a buffer */
524 if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
530 int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slot_name)
532 BMOpSlot *slot = BMO_slot_get(op, slot_name);
533 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
535 /* check if its actually a buffer */
536 if (!(slot->slot_type == BMO_OP_SLOT_MAPPING))
539 return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
542 /* inserts a key/value mapping into a mapping slot. note that it copies the
543 * value, it doesn't store a reference to it. */
545 void BMO_slot_map_insert(BMesh *UNUSED(bm), BMOperator *op, const char *slot_name,
546 void *element, void *data, int len)
548 BMOElemMapping *mapping;
549 BMOpSlot *slot = BMO_slot_get(op, slot_name);
550 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
552 mapping = (BMOElemMapping *) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
554 mapping->element = (BMHeader *) element;
556 memcpy(mapping + 1, data, len);
558 if (!slot->data.ghash) {
559 slot->data.ghash = BLI_ghash_ptr_new("bmesh slot map hash");
562 BLI_ghash_insert(slot->data.ghash, element, mapping);
566 void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slot_code, int totadd)
568 BMOpSlot *slot = &op->slots[slot_code];
572 BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
574 /* check if its actually a buffer */
575 if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
578 if (slot->flag & BMOS_DYNAMIC_ARRAY) {
579 if (slot->len >= slot->size) {
580 slot->size = (slot->size + 1 + totadd) * 2;
582 allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slot_types[slot_code].type] * slot->size;
584 tmp = slot->data.buf;
585 slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
586 memcpy(slot->data.buf, tmp, allocsize);
593 slot->flag |= BMOS_DYNAMIC_ARRAY;
595 slot->size = slot->len + 2;
597 allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slot_types[slot_code].type] * slot->len;
599 tmp = slot->data.buf;
600 slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
601 memcpy(slot->data.buf, tmp, allocsize);
604 return slot->data.buf;
608 void BMO_slot_map_to_flag(BMesh *bm, BMOperator *op, const char *slot_name,
609 const char htype, const short oflag)
612 BMOpSlot *slot = BMO_slot_get(op, slot_name);
615 BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
618 if (!slot->data.ghash) return;
620 BLI_ghashIterator_init(&it, slot->data.ghash);
621 for ( ; (ele_f = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
622 if (ele_f->head.htype & htype) {
623 BMO_elem_flag_enable(bm, ele_f, oflag);
628 static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slot_name, int len)
630 BMOpSlot *slot = BMO_slot_get(op, slot_name);
631 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
633 /* check if its actually a buffer */
634 if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
639 slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slot_type] * len);
640 return slot->data.buf;
644 * \brief BMO_ALL_TO_SLOT
646 * Copies all elements of a certain type into an operator slot.
648 void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, const char *slot_name, const char htype)
650 BMOpSlot *output = BMO_slot_get(op, slot_name);
651 int totelement = 0, i = 0;
653 if (htype & BM_VERT) totelement += bm->totvert;
654 if (htype & BM_EDGE) totelement += bm->totedge;
655 if (htype & BM_FACE) totelement += bm->totface;
661 bmo_slot_buffer_alloc(op, slot_name, totelement);
663 /* TODO - collapse these loops into one */
665 if (htype & BM_VERT) {
666 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
667 ((BMHeader **)output->data.p)[i] = ele;
672 if (htype & BM_EDGE) {
673 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
674 ((BMHeader **)output->data.p)[i] = ele;
679 if (htype & BM_FACE) {
680 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
681 ((BMHeader **)output->data.p)[i] = ele;
689 * \brief BMO_HEADERFLAG_TO_SLOT
691 * Copies elements of a certain type, which have a certain header flag
692 * enabled/disabled into a slot for an operator.
694 static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, const char *slot_name,
695 const char htype, const char hflag,
696 const short test_for_enabled)
698 BMOpSlot *output = BMO_slot_get(op, slot_name);
699 int totelement = 0, i = 0;
701 BLI_assert(ELEM(test_for_enabled, TRUE, FALSE));
703 if (test_for_enabled)
704 totelement = BM_mesh_elem_hflag_count_enabled(bm, htype, hflag, TRUE);
706 totelement = BM_mesh_elem_hflag_count_disabled(bm, htype, hflag, TRUE);
712 bmo_slot_buffer_alloc(op, slot_name, totelement);
714 /* TODO - collapse these loops into one */
716 if (htype & BM_VERT) {
717 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
718 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
719 BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
721 ((BMElem **)output->data.p)[i] = ele;
727 if (htype & BM_EDGE) {
728 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
729 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
730 BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
732 ((BMElem **)output->data.p)[i] = ele;
738 if (htype & BM_FACE) {
739 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
740 if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
741 BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
743 ((BMElem **)output->data.p)[i] = ele;
754 void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op, const char *slot_name,
755 const char htype, const char hflag)
757 bmo_slot_buffer_from_hflag(bm, op, slot_name, htype, hflag, TRUE);
760 void BMO_slot_buffer_from_disabled_hflag(BMesh *bm, BMOperator *op, const char *slot_name,
761 const char htype, const char hflag)
763 bmo_slot_buffer_from_hflag(bm, op, slot_name, htype, hflag, FALSE);
767 * Copies the values from another slot to the end of the output slot.
769 void BMO_slot_buffer_append(BMOperator *output_op, const char *output_slot_name,
770 BMOperator *other_op, const char *other_slot_name)
772 BMOpSlot *output_slot = BMO_slot_get(output_op, output_slot_name);
773 BMOpSlot *other_slot = BMO_slot_get(other_op, other_slot_name);
775 BLI_assert(output_slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF &&
776 other_slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
778 if (output_slot->len == 0) {
779 /* output slot is empty, copy rather than append */
780 BMO_slot_copy(other_op, output_op, other_slot_name, output_slot_name);
782 else if (other_slot->len != 0) {
783 int elem_size = BMO_OPSLOT_TYPEINFO[output_slot->slot_type];
784 int alloc_size = elem_size * (output_slot->len + other_slot->len);
785 /* allocate new buffer */
786 void *buf = BLI_memarena_alloc(output_op->arena, alloc_size);
789 memcpy(buf, output_slot->data.buf, elem_size * output_slot->len);
790 memcpy(((char *)buf) + elem_size * output_slot->len, other_slot->data.buf, elem_size * other_slot->len);
792 output_slot->data.buf = buf;
793 output_slot->len += other_slot->len;
798 * \brief BMO_FLAG_TO_SLOT
800 * Copies elements of a certain type, which have a certain flag set
801 * into an output slot for an operator.
803 static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op, const char *slot_name,
804 const char htype, const short oflag,
805 const short test_for_enabled)
807 BMOpSlot *slot = BMO_slot_get(op, slot_name);
808 int totelement, i = 0;
810 BLI_assert(ELEM(TRUE, FALSE, test_for_enabled));
812 if (test_for_enabled)
813 totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag);
815 totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag);
817 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
822 BMHeader **ele_array;
824 bmo_slot_buffer_alloc(op, slot_name, totelement);
826 ele_array = (BMHeader **)slot->data.p;
828 /* TODO - collapse these loops into one */
830 if (htype & BM_VERT) {
831 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
832 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
839 if (htype & BM_EDGE) {
840 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
841 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
848 if (htype & BM_FACE) {
849 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
850 if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
862 void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, const char *slot_name,
863 const char htype, const short oflag)
865 bmo_slot_buffer_from_flag(bm, op, slot_name, htype, oflag, TRUE);
868 void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op, const char *slot_name,
869 const char htype, const short oflag)
871 bmo_slot_buffer_from_flag(bm, op, slot_name, htype, oflag, FALSE);
875 * \brief BMO_FLAG_BUFFER
877 * Header Flags elements in a slots buffer, automatically
878 * using the selection API where appropriate.
880 void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slot_name,
881 const char htype, const char hflag, const char do_flush)
883 BMOpSlot *slot = BMO_slot_get(op, slot_name);
884 BMElem **data = slot->data.p;
886 const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
887 const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
889 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
891 for (i = 0; i < slot->len; i++, data++) {
892 if (!(htype & (*data)->head.htype))
895 if (do_flush_select) {
896 BM_elem_select_set(bm, *data, TRUE);
900 BM_elem_hide_set(bm, *data, FALSE);
903 BM_elem_flag_enable(*data, hflag);
908 * \brief BMO_FLAG_BUFFER
910 * Removes flags from elements in a slots buffer, automatically
911 * using the selection API where appropriate.
913 void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slot_name,
914 const char htype, const char hflag, const char do_flush)
916 BMOpSlot *slot = BMO_slot_get(op, slot_name);
917 BMElem **data = slot->data.p;
919 const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
920 const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
922 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
924 for (i = 0; i < slot->len; i++, data++) {
925 if (!(htype & (*data)->head.htype))
928 if (do_flush_select) {
929 BM_elem_select_set(bm, *data, FALSE);
933 BM_elem_hide_set(bm, *data, FALSE);
936 BM_elem_flag_disable(*data, hflag);
940 int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
946 const int len = bmesh_disk_count(v);
949 for (i = 0, curedge = v->e; i < len; i++) {
950 if (BMO_elem_flag_test(bm, curedge, oflag))
952 curedge = bmesh_disk_edge_next(curedge, v);
960 * \brief BMO_FLAG_BUFFER
962 * Flags elements in a slots buffer
964 void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slot_name,
965 const char htype, const short oflag)
967 BMOpSlot *slot = BMO_slot_get(op, slot_name);
968 BMHeader **data = slot->data.p;
971 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
973 for (i = 0; i < slot->len; i++) {
974 if (!(htype & data[i]->htype))
977 BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
982 * \brief BMO_FLAG_BUFFER
984 * Removes flags from elements in a slots buffer
986 void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slot_name,
987 const char htype, const short oflag)
989 BMOpSlot *slot = BMO_slot_get(op, slot_name);
990 BMHeader **data = slot->data.p;
993 BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
995 for (i = 0; i < slot->len; i++) {
996 if (!(htype & data[i]->htype))
999 BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
1005 * \brief ALLOC/FREE FLAG LAYER
1007 * Used by operator stack to free/allocate
1008 * private flag data. This is allocated
1009 * using a mempool so the allocation/frees
1010 * should be quite fast.
1013 * Investigate not freeing flag layers until
1014 * all operators have been executed. This would
1015 * save a lot of realloc potentially.
1017 static void bmo_flag_layer_alloc(BMesh *bm)
1020 /* set the index values since we are looping over all data anyway,
1021 * may save time later on */
1025 BLI_mempool *oldpool = bm->toolflagpool; /* old flag pool */
1026 BLI_mempool *newpool;
1029 /* store memcpy size for reuse */
1030 const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
1034 /* allocate new flag poo */
1035 bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, 512, 512, 0);
1037 /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
1038 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1039 oldflags = ele->oflags;
1040 ele->oflags = BLI_mempool_calloc(newpool);
1041 memcpy(ele->oflags, oldflags, old_totflags_size);
1042 BM_elem_index_set(ele, i); /* set_inline */
1044 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1045 oldflags = ele->oflags;
1046 ele->oflags = BLI_mempool_calloc(newpool);
1047 memcpy(ele->oflags, oldflags, old_totflags_size);
1048 BM_elem_index_set(ele, i); /* set_inline */
1050 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1051 oldflags = ele->oflags;
1052 ele->oflags = BLI_mempool_calloc(newpool);
1053 memcpy(ele->oflags, oldflags, old_totflags_size);
1054 BM_elem_index_set(ele, i); /* set_inline */
1057 bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1059 BLI_mempool_destroy(oldpool);
1062 static void bmo_flag_layer_free(BMesh *bm)
1065 /* set the index values since we are looping over all data anyway,
1066 * may save time later on */
1070 BLI_mempool *oldpool = bm->toolflagpool;
1071 BLI_mempool *newpool;
1074 /* store memcpy size for reuse */
1075 const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
1077 /* de-increment the totflags first.. */
1079 /* allocate new flag poo */
1080 bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, BLI_MEMPOOL_SYSMALLOC);
1082 /* now go through and memcpy all the flag */
1083 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1084 oldflags = ele->oflags;
1085 ele->oflags = BLI_mempool_calloc(newpool);
1086 memcpy(ele->oflags, oldflags, new_totflags_size);
1087 BM_elem_index_set(ele, i); /* set_inline */
1089 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1090 oldflags = ele->oflags;
1091 ele->oflags = BLI_mempool_calloc(newpool);
1092 memcpy(ele->oflags, oldflags, new_totflags_size);
1093 BM_elem_index_set(ele, i); /* set_inline */
1095 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1096 oldflags = ele->oflags;
1097 ele->oflags = BLI_mempool_calloc(newpool);
1098 memcpy(ele->oflags, oldflags, new_totflags_size);
1099 BM_elem_index_set(ele, i); /* set_inline */
1102 bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1104 BLI_mempool_destroy(oldpool);
1107 static void bmo_flag_layer_clear(BMesh *bm)
1110 /* set the index values since we are looping over all data anyway,
1111 * may save time later on */
1115 const int totflags_offset = bm->totflags - 1;
1117 /* now go through and memcpy all the flag */
1118 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1119 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1120 BM_elem_index_set(ele, i); /* set_inline */
1122 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1123 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1124 BM_elem_index_set(ele, i); /* set_inline */
1126 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1127 memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1128 BM_elem_index_set(ele, i); /* set_inline */
1131 bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1134 void *BMO_slot_buffer_elem_first(BMOperator *op, const char *slot_name)
1136 BMOpSlot *slot = BMO_slot_get(op, slot_name);
1138 if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF)
1141 return slot->data.buf ? *(void **)slot->data.buf : NULL;
1145 * \brief New Iterator
1147 * \param restrictmask restricts the iteration to certain element types
1148 * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
1149 * over an element buffer (not a mapping). */
1150 void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
1151 const char *slot_name, const char restrictmask)
1153 BMOpSlot *slot = BMO_slot_get(op, slot_name);
1155 memset(iter, 0, sizeof(BMOIter));
1159 iter->restrictmask = restrictmask;
1161 if (iter->slot->slot_type == BMO_OP_SLOT_MAPPING) {
1162 if (iter->slot->data.ghash) {
1163 BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1170 return BMO_iter_step(iter);
1173 void *BMO_iter_step(BMOIter *iter)
1175 if (iter->slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
1178 if (iter->cur >= iter->slot->len) {
1182 h = ((void **)iter->slot->data.buf)[iter->cur++];
1183 while (!(iter->restrictmask & h->htype)) {
1184 if (iter->cur >= iter->slot->len) {
1188 h = ((void **)iter->slot->data.buf)[iter->cur++];
1193 else if (iter->slot->slot_type == BMO_OP_SLOT_MAPPING) {
1194 BMOElemMapping *map;
1195 void *ret = BLI_ghashIterator_getKey(&iter->giter);
1196 map = BLI_ghashIterator_getValue(&iter->giter);
1198 iter->val = map + 1;
1200 BLI_ghashIterator_step(&iter->giter);
1208 /* used for iterating over mapping */
1209 void *BMO_iter_map_value(BMOIter *iter)
1214 void *BMO_iter_map_value_p(BMOIter *iter)
1216 return *((void **)iter->val);
1219 float BMO_iter_map_value_f(BMOIter *iter)
1221 return *((float *)iter->val);
1225 typedef struct BMOpError {
1226 struct BMOpError *next, *prev;
1232 void BMO_error_clear(BMesh *bm)
1234 while (BMO_error_pop(bm, NULL, NULL));
1237 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1239 BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1241 err->errorcode = errcode;
1242 if (!msg) msg = bmo_error_messages[errcode];
1246 BLI_addhead(&bm->errorstack, err);
1249 int BMO_error_occurred(BMesh *bm)
1251 return bm->errorstack.first != NULL;
1254 /* returns error code or 0 if no erro */
1255 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1257 BMOpError *err = bm->errorstack.first;
1262 if (msg) *msg = err->msg;
1263 if (op) *op = err->op;
1265 return err->errorcode;
1268 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1270 int errorcode = BMO_error_get(bm, msg, op);
1273 BMOpError *err = bm->errorstack.first;
1275 BLI_remlink(&bm->errorstack, bm->errorstack.first);
1283 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1285 static int bmo_name_to_slotcode(BMOpDefine *def, const char *name)
1289 for (i = 0; def->slot_types[i].type; i++) {
1290 if (!strncmp(name, def->slot_types[i].name, MAX_SLOTNAME)) {
1298 static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name)
1300 int i = bmo_name_to_slotcode(def, name);
1302 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1308 static int bmo_opname_to_opcode(const char *opname)
1312 for (i = 0; i < bmesh_total_ops; i++) {
1313 if (!strcmp(opname, opdefines[i]->name)) {
1318 fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1323 * BMO_op_callf(bm, "del %i %hv", DEL_ONLYFACES, BM_ELEM_SELECT);
1326 * b - boolean (same as int but 1/0 only)
1328 * hv - header flagged verts (hflag)
1329 * he - header flagged edges (hflag)
1330 * hf - header flagged faces (hflag)
1331 * fv - flagged verts (oflag)
1332 * fe - flagged edges (oflag)
1333 * ff - flagged faces (oflag)
1335 * capitals - H, F to use the flag flipped (when the flag is off)
1336 * Hv, He, Hf, Fv, Fe, Ff,
1339 int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1342 char *opname, *ofmt, *fmt;
1343 char slot_name[64] = {0};
1344 int i /*, n = strlen(fmt) */, stop /*, slot_code = -1 */, type, state;
1349 /* basic useful info to help find where bmop formatting strings fail */
1350 const char *err_reason = "Unknown";
1353 #define GOTO_ERROR(reason) \
1355 err_reason = reason; \
1356 lineno = __LINE__; \
1360 /* we muck around in here, so dup i */
1361 fmt = ofmt = BLI_strdup(_fmt);
1363 /* find operator name */
1364 i = strcspn(fmt, " ");
1367 if (!opname[i]) noslot = 1;
1370 fmt += i + (noslot ? 0 : 1);
1372 i = bmo_opname_to_opcode(opname);
1379 BMO_op_init(bm, op, opname);
1383 state = 1; /* 0: not inside slot_code name, 1: inside slot_code name */
1387 /* jump past leading whitespac */
1388 i = strspn(fmt, " ");
1391 /* ignore trailing whitespac */
1395 /* find end of slot name, only "slot=%f", can be used */
1396 i = strcspn(fmt, "=");
1398 GOTO_ERROR("could not match end of slot name");
1403 if (bmo_name_to_slotcode_check(def, fmt) < 0) {
1404 GOTO_ERROR("name to slot code check failed");
1407 BLI_strncpy(slot_name, fmt, sizeof(slot_name));
1424 if (c == '3') size = 3;
1425 else if (c == '4') size = 4;
1426 else GOTO_ERROR("matrix size was not 3 or 4");
1428 BMO_slot_mat_set(op, slot_name, va_arg(vlist, void *), size);
1433 BMO_slot_vec_set(op, slot_name, va_arg(vlist, float *));
1438 BMHeader *ele = va_arg(vlist, void *);
1439 BMOpSlot *slot = BMO_slot_get(op, slot_name);
1441 slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1443 *((void **)slot->data.buf) = ele;
1449 BMOperator *op2 = va_arg(vlist, void *);
1450 const char *slot_name2 = va_arg(vlist, char *);
1452 BMO_slot_copy(op2, op, slot_name2, slot_name);
1457 BMO_slot_int_set(op, slot_name, va_arg(vlist, int));
1461 BMO_slot_bool_set(op, slot_name, va_arg(vlist, int));
1465 BMO_slot_ptr_set(op, slot_name, va_arg(vlist, void *));
1475 if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\0') {
1476 BMO_slot_float_set(op, slot_name, va_arg(vlist, double));
1482 switch (NEXT_CHAR(fmt)) {
1483 case 'f': htype |= BM_FACE; break;
1484 case 'e': htype |= BM_EDGE; break;
1485 case 'v': htype |= BM_VERT; break;
1498 BMO_slot_buffer_from_enabled_hflag(bm, op, slot_name, htype, va_arg(vlist, int));
1500 else if (type == 'H') {
1501 BMO_slot_buffer_from_disabled_hflag(bm, op, slot_name, htype, va_arg(vlist, int));
1503 else if (type == 'a') {
1504 BMO_slot_buffer_from_all(bm, op, slot_name, htype);
1506 else if (type == 'f') {
1507 BMO_slot_buffer_from_enabled_flag(bm, op, slot_name, htype, va_arg(vlist, int));
1509 else if (type == 'F') {
1510 BMO_slot_buffer_from_disabled_flag(bm, op, slot_name, htype, va_arg(vlist, int));
1518 "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1519 __func__, *fmt, (int)(fmt - ofmt), ofmt);
1530 /* non urgent todo - explain exactly what is failing */
1531 fprintf(stderr, "%s: error parsing formatting string\n", __func__);
1533 fprintf(stderr, "string: '%s', position %d\n", _fmt, (int)(fmt - ofmt));
1534 fprintf(stderr, " ");
1536 int pos = (int)(fmt - ofmt);
1538 for (i = 0; i < pos; i++) {
1539 fprintf(stderr, " ");
1541 fprintf(stderr, "^\n");
1544 fprintf(stderr, "source code: %s:%d\n", __FILE__, lineno);
1546 fprintf(stderr, "reason: %s\n", err_reason);
1551 BMO_op_finish(bm, op);
1559 int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1563 va_start(list, fmt);
1564 if (!BMO_op_vinitf(bm, op, fmt, list)) {
1565 printf("%s: failed\n", __func__);
1574 int BMO_op_callf(BMesh *bm, const char *fmt, ...)
1579 va_start(list, fmt);
1580 if (!BMO_op_vinitf(bm, &op, fmt, list)) {
1581 printf("%s: failed, format is:\n \"%s\"\n", __func__, fmt);
1586 BMO_op_exec(bm, &op);
1587 BMO_op_finish(bm, &op);