Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2012-02-19 22:31:04 +0400
committerCampbell Barton <ideasman42@gmail.com>2012-02-19 22:31:04 +0400
commitafc56a0b10b52d2c8bdfd44257624d776db72f79 (patch)
tree25d194e29b2708ac1143b3dde6dfbeec7ef1d876 /source/blender/bmesh/intern/bmesh_operators.c
parentd6deca4e9d6bc7faff98644286571c7934324a9d (diff)
copying bmesh dir on its own from bmesh branch
Diffstat (limited to 'source/blender/bmesh/intern/bmesh_operators.c')
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c1376
1 files changed, 1376 insertions, 0 deletions
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
new file mode 100644
index 00000000000..66222c39c68
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -0,0 +1,1376 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_operators.c
+ * \ingroup bmesh
+ *
+ * BMesh operator access.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_listbase.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/* forward declarations */
+static void bmo_flag_layer_alloc(BMesh *bm);
+static void bmo_flag_layer_free(BMesh *bm);
+static void bmo_flag_layer_clear(BMesh *bm);
+static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name);
+static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name);
+static int bmesh_opname_to_opcode(const char *opname);
+
+static const char *bmo_error_messages[] = {
+ NULL,
+ "Self intersection error",
+ "Could not dissolve vert",
+ "Could not connect vertices",
+ "Could not traverse mesh",
+ "Could not dissolve faces",
+ "Could not dissolve vertices",
+ "Tesselation error",
+ "Can not deal with non-manifold geometry",
+ "Invalid selection",
+ "Internal mesh error",
+};
+
+
+/* operator slot type information - size of one element of the type given. */
+const int BMO_OPSLOT_TYPEINFO[] = {
+ 0,
+ sizeof(int),
+ sizeof(float),
+ sizeof(void *),
+ 0, /* unused */
+ 0, /* unused */
+ 0, /* unused */
+ sizeof(void *), /* pointer buffer */
+ sizeof(BMOElemMapping)
+};
+
+/* Dummy slot so there is something to return when slot name lookup fails */
+static BMOpSlot BMOpEmptySlot = {0};
+
+void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
+{
+ op->flag |= op_flag;
+}
+
+void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
+{
+ op->flag &= ~op_flag;
+}
+
+/*
+ * BMESH OPSTACK PUSH
+ *
+ * Pushes the opstack down one level
+ * and allocates a new flag layer if
+ * appropriate.
+ */
+void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
+{
+ bm->stackdepth++;
+
+ /* add flag layer, if appropriate */
+ if (bm->stackdepth > 1)
+ bmo_flag_layer_alloc(bm);
+ else
+ bmo_flag_layer_clear(bm);
+}
+
+/*
+ * BMESH OPSTACK POP
+ *
+ * Pops the opstack one level
+ * and frees a flag layer if appropriate
+ * BMESH_TODO: investigate NOT freeing flag
+ * layers.
+ */
+void BMO_pop(BMesh *bm)
+{
+ if (bm->stackdepth > 1)
+ bmo_flag_layer_free(bm);
+
+ bm->stackdepth--;
+}
+
+/*
+ * BMESH OPSTACK INIT OP
+ *
+ * Initializes an operator structure
+ * to a certain type
+ */
+void BMO_op_init(BMesh *bm, BMOperator *op, const char *opname)
+{
+ int i, opcode = bmesh_opname_to_opcode(opname);
+
+#ifdef DEBUG
+ BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
+#else
+ (void)bm;
+#endif
+
+ if (opcode == -1) {
+ opcode = 0; /* error!, already printed, have a better way to handle this? */
+ }
+
+ memset(op, 0, sizeof(BMOperator));
+ op->type = opcode;
+ op->flag = opdefines[opcode]->flag;
+
+ /* initialize the operator slot types */
+ for (i = 0; opdefines[opcode]->slottypes[i].type; i++) {
+ op->slots[i].slottype = opdefines[opcode]->slottypes[i].type;
+ op->slots[i].index = i;
+ }
+
+ /* callback */
+ op->exec = opdefines[opcode]->exec;
+
+ /* memarena, used for operator's slot buffers */
+ op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bmesh operator");
+ BLI_memarena_use_calloc (op->arena);
+}
+
+/*
+ * BMESH OPSTACK EXEC OP
+ *
+ * Executes a passed in operator. This handles
+ * the allocation and freeing of temporary flag
+ * layers and starting/stopping the modelling
+ * loop. Can be called from other operators
+ * exec callbacks as well.
+ */
+void BMO_op_exec(BMesh *bm, BMOperator *op)
+{
+
+ BMO_push(bm, op);
+
+ if (bm->stackdepth == 2)
+ bmesh_begin_edit(bm, op->flag);
+ op->exec(bm, op);
+
+ if (bm->stackdepth == 2)
+ bmesh_end_edit(bm, op->flag);
+
+ BMO_pop(bm);
+}
+
+/*
+ * BMESH OPSTACK FINISH OP
+ *
+ * Does housekeeping chores related to finishing
+ * up an operator.
+ */
+void BMO_op_finish(BMesh *bm, BMOperator *op)
+{
+ BMOpSlot *slot;
+ int i;
+
+ for (i = 0; opdefines[op->type]->slottypes[i].type; i++) {
+ slot = &op->slots[i];
+ if (slot->slottype == BMO_OP_SLOT_MAPPING) {
+ if (slot->data.ghash)
+ BLI_ghash_free(slot->data.ghash, NULL, NULL);
+ }
+ }
+
+ BLI_memarena_free(op->arena);
+
+#ifdef DEBUG
+ BM_ELEM_INDEX_VALIDATE(bm, "post bmo", opdefines[op->type]->name);
+#else
+ (void)bm;
+#endif
+}
+
+/*
+ * BMESH OPSTACK HAS SLOT
+ *
+ * Returns 1 if the named slot exists on the given operator,
+ * otherwise returns 0.
+ */
+int BMO_slot_exists(BMOperator *op, const char *slotname)
+{
+ int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname);
+ return (slotcode >= 0);
+}
+
+/*
+ * BMESH OPSTACK GET SLOT
+ *
+ * Returns a pointer to the slot of
+ * type 'slotcode'
+ */
+BMOpSlot *BMO_slot_get(BMOperator *op, const char *slotname)
+{
+ int slotcode = bmesh_name_to_slotcode_check(opdefines[op->type], slotname);
+
+ if (slotcode < 0) {
+ return &BMOpEmptySlot;
+ }
+
+ return &(op->slots[slotcode]);
+}
+
+/*
+ * BMESH OPSTACK COPY SLOT
+ *
+ * Copies data from one slot to another
+ */
+void BMO_slot_copy(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
+{
+ BMOpSlot *source_slot = BMO_slot_get(source_op, src);
+ BMOpSlot *dest_slot = BMO_slot_get(dest_op, dst);
+
+ if (source_slot == dest_slot)
+ return;
+
+ if (source_slot->slottype != dest_slot->slottype)
+ return;
+
+ if (dest_slot->slottype > BMO_OP_SLOT_VEC) {
+ if (dest_slot->slottype != BMO_OP_SLOT_MAPPING) {
+ /* do buffer copy */
+ dest_slot->data.buf = NULL;
+ dest_slot->len = source_slot->len;
+ if (dest_slot->len) {
+ const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
+ dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
+ memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
+ }
+ }
+ else {
+ GHashIterator it;
+ BMOElemMapping *srcmap, *dstmap;
+
+ /* sanity check */
+ if (!source_slot->data.ghash) return;
+
+ if (!dest_slot->data.ghash) {
+ dest_slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
+ BLI_ghashutil_ptrcmp, "bmesh operator 2");
+ }
+
+ BLI_ghashIterator_init(&it, source_slot->data.ghash);
+ for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
+ BLI_ghashIterator_step(&it))
+ {
+ dstmap = BLI_memarena_alloc(dest_op->arena, sizeof(*dstmap) + srcmap->len);
+
+ dstmap->element = srcmap->element;
+ dstmap->len = srcmap->len;
+ memcpy(dstmap + 1, srcmap + 1, srcmap->len);
+
+ BLI_ghash_insert(dest_slot->data.ghash, dstmap->element, dstmap);
+ }
+ }
+ }
+ else {
+ dest_slot->data = source_slot->data;
+ }
+}
+
+/*
+ * BMESH OPSTACK SET XXX
+ *
+ * Sets the value of a slot depending on it's type
+ *
+ */
+
+void BMO_slot_float_set(BMOperator *op, const char *slotname, const float f)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_FLT))
+ return;
+
+ slot->data.f = f;
+}
+
+void BMO_slot_int_set(BMOperator *op, const char *slotname, const int i)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_INT))
+ return;
+
+ slot->data.i = i;
+}
+
+/* only supports square mats */
+void BMO_slot_mat_set(struct BMOperator *op, const char *slotname, const float *mat, int size)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_MAT))
+ return;
+
+ slot->len = 4;
+ slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
+
+ if (size == 4) {
+ memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
+ }
+ else if (size == 3) {
+ copy_m4_m3(slot->data.p, (float (*)[3])mat);
+ }
+ else {
+ fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
+
+ memset(slot->data.p, 0, sizeof(float) * 4 * 4);
+ }
+}
+
+void BMO_slot_mat4_get(struct BMOperator *op, const char *slotname, float r_mat[4][4])
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_MAT))
+ return;
+
+ copy_m4_m4(r_mat, (float (*)[4])slot->data.p);
+}
+
+void BMO_slot_mat3_set(struct BMOperator *op, const char *slotname, float r_mat[3][3])
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_MAT))
+ return;
+
+ copy_m3_m4(r_mat, slot->data.p);
+}
+
+void BMO_slot_ptr_set(BMOperator *op, const char *slotname, void *p)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_PNT))
+ return;
+
+ slot->data.p = p;
+}
+
+void BMO_slot_vec_set(BMOperator *op, const char *slotname, const float vec[3])
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_VEC))
+ return;
+
+ copy_v3_v3(slot->data.vec, vec);
+}
+
+
+float BMO_slot_float_get(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_FLT))
+ return 0.0f;
+
+ return slot->data.f;
+}
+
+int BMO_slot_int_get(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_INT))
+ return 0;
+
+ return slot->data.i;
+}
+
+
+void *BMO_slot_ptr_get(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_PNT))
+ return NULL;
+
+ return slot->data.p;
+}
+
+void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3])
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_VEC))
+ return;
+
+ copy_v3_v3(r_vec, slot->data.vec);
+}
+
+/*
+ * BMO_COUNTFLAG
+ *
+ * Counts the number of elements of a certain type that
+ * have a specific flag set.
+ *
+ */
+
+int BMO_mesh_flag_count(BMesh *bm, const short oflag, const char htype)
+{
+ BMIter elements;
+ int count = 0;
+ BMElemF *ele_f;
+
+ if (htype & BM_VERT) {
+ for (ele_f = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, ele_f, oflag))
+ count++;
+ }
+ }
+ if (htype & BM_EDGE) {
+ for (ele_f = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, ele_f, oflag))
+ count++;
+ }
+ }
+ if (htype & BM_FACE) {
+ for (ele_f = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, ele_f, oflag))
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
+{
+ const char iter_types[3] = {BM_VERTS_OF_MESH,
+ BM_EDGES_OF_MESH,
+ BM_FACES_OF_MESH};
+
+ const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
+
+ BMIter iter;
+ BMElemF *ele;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (htype & flag_types[i]) {
+ BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
+ BMO_elem_flag_disable(bm, ele, oflag);
+ }
+ }
+ }
+}
+
+int BMO_slot_buf_count(struct BMesh *UNUSED(bm), struct BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ /* check if its actually a buffer */
+ if (!(slot->slottype > BMO_OP_SLOT_VEC))
+ return 0;
+
+ return slot->len;
+}
+
+int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ /* check if its actually a buffer */
+ if (!(slot->slottype == BMO_OP_SLOT_MAPPING))
+ return 0;
+
+ return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
+}
+
+#if 0
+void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd)
+{
+ BMOpSlot *slot = &op->slots[slotcode];
+ void *tmp;
+ ssize_t allocsize;
+
+ /* check if its actually a buffer */
+ if (!(slot->slottype > BMO_OP_SLOT_VEC))
+ return NULL;
+
+ if (slot->flag & BMOS_DYNAMIC_ARRAY) {
+ if (slot->len >= slot->size) {
+ slot->size = (slot->size + 1 + totadd) * 2;
+
+ allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size;
+
+ tmp = slot->data.buf;
+ slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
+ memcpy(slot->data.buf, tmp, allocsize);
+ MEM_freeN(tmp);
+ }
+
+ slot->len += totadd;
+ }
+ else {
+ slot->flag |= BMOS_DYNAMIC_ARRAY;
+ slot->len += totadd;
+ slot->size = slot->len + 2;
+
+ allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len;
+
+ tmp = slot->data.buf;
+ slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
+ memcpy(slot->data.buf, tmp, allocsize);
+ }
+
+ return slot->data.buf;
+}
+#endif
+
+void BMO_slot_map_to_flag(struct BMesh *bm, struct BMOperator *op,
+ const char *slotname, const short oflag)
+{
+ GHashIterator it;
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMElemF *ele_f;
+
+ /* sanity check */
+ if (slot->slottype != BMO_OP_SLOT_MAPPING) return;
+ if (!slot->data.ghash) return;
+
+ BLI_ghashIterator_init(&it, slot->data.ghash);
+ for ( ; (ele_f = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
+ BMO_elem_flag_enable(bm, ele_f, oflag);
+ }
+}
+
+static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slotname, int len)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ /* check if its actually a buffer */
+ if (!(slot->slottype > BMO_OP_SLOT_VEC))
+ return NULL;
+
+ slot->len = len;
+ if (len)
+ slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slottype] * len);
+ return slot->data.buf;
+}
+
+/*
+ * BMO_ALL_TO_SLOT
+ *
+ * Copies all elements of a certain type into an operator slot.
+ *
+ */
+
+static void BMO_slot_from_all(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_slot_get(op, slotname);
+ int totelement = 0, i = 0;
+
+ if (htype & BM_VERT) totelement += bm->totvert;
+ if (htype & BM_EDGE) totelement += bm->totedge;
+ if (htype & BM_FACE) totelement += bm->totface;
+
+ if (totelement) {
+ bmo_slot_buffer_alloc(op, slotname, totelement);
+
+ if (htype & BM_VERT) {
+ for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+
+ if (htype & BM_EDGE) {
+ for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+
+ if (htype & BM_FACE) {
+ for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+}
+
+/*
+ * BMO_HEADERFLAG_TO_SLOT
+ *
+ * Copies elements of a certain type, which have a certain header flag set
+ * into a slot for an operator.
+ */
+
+void BMO_slot_from_hflag(BMesh *bm, BMOperator *op, const char *slotname,
+ const char hflag, const char htype)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_slot_get(op, slotname);
+ int totelement = 0, i = 0;
+
+ totelement = BM_mesh_count_flag(bm, htype, hflag, 1);
+
+ if (totelement) {
+ bmo_slot_buffer_alloc(op, slotname, totelement);
+
+ if (htype & BM_VERT) {
+ for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (htype & BM_EDGE) {
+ for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (htype & BM_FACE) {
+ for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+ }
+ else {
+ output->len = 0;
+ }
+}
+
+/*
+ * BMO_FLAG_TO_SLOT
+ *
+ * Copies elements of a certain type, which have a certain flag set
+ * into an output slot for an operator.
+ */
+void BMO_slot_from_flag(BMesh *bm, BMOperator *op, const char *slotname,
+ const short oflag, const char htype)
+{
+ BMIter elements;
+ BMHeader *ele;
+ BMOpSlot *output = BMO_slot_get(op, slotname);
+ int totelement = BMO_mesh_flag_count(bm, oflag, htype), i = 0;
+
+ if (totelement) {
+ bmo_slot_buffer_alloc(op, slotname, totelement);
+
+ if (htype & BM_VERT) {
+ for (ele = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
+ ((BMHeader **)output->data.p)[i] = ele;
+ i++;
+ }
+ }
+ }
+
+ if (htype & BM_EDGE) {
+ for (ele = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
+ ((BMHeader **)output->data.p)[i] = ele;
+ i++;
+ }
+ }
+ }
+
+ if (htype & BM_FACE) {
+ for (ele = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
+ ((BMHeader **)output->data.p)[i] = ele;
+ i++;
+ }
+ }
+ }
+ }
+ else {
+ output->len = 0;
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Header Flags elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
+void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slotname,
+ const char hflag, const char htype)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for (i = 0; i < slot->len; i++) {
+ if (!(htype & data[i]->htype))
+ continue;
+
+ if (hflag & BM_ELEM_SELECT) {
+ BM_elem_select_set(bm, data[i], TRUE);
+ }
+ BM_elem_flag_enable(data[i], hflag);
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
+void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slotname,
+ const char hflag, const char htype)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for (i = 0; i < slot->len; i++) {
+ if (!(htype & data[i]->htype))
+ continue;
+
+ if (hflag & BM_ELEM_SELECT) {
+ BM_elem_select_set(bm, data[i], FALSE);
+ }
+
+ BM_elem_flag_disable(data[i], hflag);
+ }
+}
+int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
+{
+ int count = 0;
+
+ if (v->e) {
+ BMEdge *curedge;
+ const int len = bmesh_disk_count(v);
+ int i;
+
+ for (i = 0, curedge = v->e; i < len; i++) {
+ if (BMO_elem_flag_test(bm, curedge, oflag))
+ count++;
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }
+ }
+
+ return count;
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Flags elements in a slots buffer
+ */
+void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slotname,
+ const short oflag, const char htype)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for (i = 0; i < slot->len; i++) {
+ if (!(htype & data[i]->htype))
+ continue;
+
+ BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer
+ */
+void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slotname,
+ const short oflag, const char htype)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for (i = 0; i < slot->len; i++) {
+ if (!(htype & data[i]->htype))
+ continue;
+
+ BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
+ }
+}
+
+
+/*
+ *
+ * ALLOC/FREE FLAG LAYER
+ *
+ * Used by operator stack to free/allocate
+ * private flag data. This is allocated
+ * using a mempool so the allocation/frees
+ * should be quite fast.
+ *
+ * BMESH_TODO:
+ * Investigate not freeing flag layers until
+ * all operators have been executed. This would
+ * save a lot of realloc potentially.
+ */
+static void bmo_flag_layer_alloc(BMesh *bm)
+{
+ BMElemF *ele;
+ /* set the index values since we are looping over all data anyway,
+ * may save time later on */
+ int i;
+
+ BMIter iter;
+ BLI_mempool *oldpool = bm->toolflagpool; /* old flag pool */
+ BLI_mempool *newpool;
+ void *oldflags;
+
+ /* store memcpy size for reuse */
+ const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
+
+ bm->totflags++;
+
+ /* allocate new flag poo */
+ bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, FALSE, FALSE);
+
+ /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
+ for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, old_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, old_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, old_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+
+ bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
+
+ BLI_mempool_destroy(oldpool);
+}
+
+static void bmo_flag_layer_free(BMesh *bm)
+{
+ BMElemF *ele;
+ /* set the index values since we are looping over all data anyway,
+ * may save time later on */
+ int i;
+
+ BMIter iter;
+ BLI_mempool *oldpool = bm->toolflagpool;
+ BLI_mempool *newpool;
+ void *oldflags;
+
+ /* store memcpy size for reuse */
+ const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
+
+ /* de-increment the totflags first.. */
+ bm->totflags--;
+ /* allocate new flag poo */
+ bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, TRUE, FALSE);
+
+ /* now go through and memcpy all the flag */
+ for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, new_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, new_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, new_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+
+ bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
+
+ BLI_mempool_destroy(oldpool);
+}
+
+static void bmo_flag_layer_clear(BMesh *bm)
+{
+ BMElemF *ele;
+ /* set the index values since we are looping over all data anyway,
+ * may save time later on */
+ int i;
+
+ BMIter iter;
+ const int totflags_offset = bm->totflags - 1;
+
+ /* now go through and memcpy all the flag */
+ for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+
+ bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
+}
+
+void *BMO_slot_elem_first(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
+ return NULL;
+
+ return slot->data.buf ? *(void **)slot->data.buf : NULL;
+}
+
+void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
+ const char *slotname, const char restrictmask)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ memset(iter, 0, sizeof(BMOIter));
+
+ iter->slot = slot;
+ iter->cur = 0;
+ iter->restrictmask = restrictmask;
+
+ if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
+ if (iter->slot->data.ghash) {
+ BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ return BMO_iter_step(iter);
+}
+
+void *BMO_iter_step(BMOIter *iter)
+{
+ if (iter->slot->slottype == BMO_OP_SLOT_ELEMENT_BUF) {
+ BMHeader *h;
+
+ if (iter->cur >= iter->slot->len) {
+ return NULL;
+ }
+
+ h = ((void **)iter->slot->data.buf)[iter->cur++];
+ while (!(iter->restrictmask & h->htype)) {
+ if (iter->cur >= iter->slot->len) {
+ return NULL;
+ }
+
+ h = ((void **)iter->slot->data.buf)[iter->cur++];
+ }
+
+ return h;
+ }
+ else if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
+ struct BMOElemMapping *map;
+ void *ret = BLI_ghashIterator_getKey(&iter->giter);
+ map = BLI_ghashIterator_getValue(&iter->giter);
+
+ iter->val = map + 1;
+
+ BLI_ghashIterator_step(&iter->giter);
+
+ return ret;
+ }
+
+ return NULL;
+}
+
+/* used for iterating over mapping */
+void *BMO_iter_map_value(BMOIter *iter)
+{
+ return iter->val;
+}
+
+void *BMO_iter_map_value_p(BMOIter *iter)
+{
+ return *((void **)iter->val);
+}
+
+float BMO_iter_map_value_f(BMOIter *iter)
+{
+ return *((float *)iter->val);
+}
+
+/* error syste */
+typedef struct BMOpError {
+ struct BMOpError *next, *prev;
+ int errorcode;
+ BMOperator *op;
+ const char *msg;
+} BMOpError;
+
+void BMO_error_clear(BMesh *bm)
+{
+ while (BMO_error_pop(bm, NULL, NULL));
+}
+
+void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
+{
+ BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
+
+ err->errorcode = errcode;
+ if (!msg) msg = bmo_error_messages[errcode];
+ err->msg = msg;
+ err->op = owner;
+
+ BLI_addhead(&bm->errorstack, err);
+}
+
+int BMO_error_occurred(BMesh *bm)
+{
+ return bm->errorstack.first != NULL;
+}
+
+/* returns error code or 0 if no erro */
+int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
+{
+ BMOpError *err = bm->errorstack.first;
+ if (!err) {
+ return 0;
+ }
+
+ if (msg) *msg = err->msg;
+ if (op) *op = err->op;
+
+ return err->errorcode;
+}
+
+int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
+{
+ int errorcode = BMO_error_get(bm, msg, op);
+
+ if (errorcode) {
+ BMOpError *err = bm->errorstack.first;
+
+ BLI_remlink(&bm->errorstack, bm->errorstack.first);
+ MEM_freeN(err);
+ }
+
+ return errorcode;
+}
+
+/* example:
+ * BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_ELEM_SELECT);
+ *
+ * d - int
+ * i - int
+ * f - float
+ * hv - header flagged verts
+ * he - header flagged edges
+ * hf - header flagged faces
+ * fv - flagged verts
+ * fe - flagged edges
+ * ff - flagged faces
+ */
+
+#define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
+
+static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name)
+{
+ int i;
+
+ for (i = 0; def->slottypes[i].type; i++) {
+ if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name)
+{
+ int i = bmesh_name_to_slotcode(def, name);
+ if (i < 0) {
+ fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
+ }
+
+ return i;
+}
+
+static int bmesh_opname_to_opcode(const char *opname)
+{
+ int i;
+
+ for (i = 0; i < bmesh_total_ops; i++) {
+ if (!strcmp(opname, opdefines[i]->name)) {
+ return i;
+ }
+ }
+
+ fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
+ return -1;
+}
+
+int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
+{
+ BMOpDefine *def;
+ char *opname, *ofmt, *fmt;
+ char slotname[64] = {0};
+ int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, ret, type, state;
+ int noslot = 0;
+
+
+ /* basic useful info to help find where bmop formatting strings fail */
+ int lineno = -1;
+# define GOTO_ERROR { lineno = __LINE__; goto error; }
+
+
+ /* we muck around in here, so dup i */
+ fmt = ofmt = BLI_strdup(_fmt);
+
+ /* find operator nam */
+ i = strcspn(fmt, " \t");
+
+ opname = fmt;
+ if (!opname[i]) noslot = 1;
+ opname[i] = '\0';
+
+ fmt += i + (noslot ? 0 : 1);
+
+ i = bmesh_opname_to_opcode(opname);
+
+ if (i == -1) {
+ MEM_freeN(ofmt);
+ return FALSE;
+ }
+
+ BMO_op_init(bm, op, opname);
+ def = opdefines[i];
+
+ i = 0;
+ state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
+
+ while (*fmt) {
+ if (state) {
+ /* jump past leading whitespac */
+ i = strspn(fmt, " \t");
+ fmt += i;
+
+ /* ignore trailing whitespac */
+ if (!fmt[i])
+ break;
+
+ /* find end of slot name. currently this is
+ * a little flexible, allowing "slot=%f",
+ * "slot %f", "slot%f", and "slot\t%f". */
+ i = strcspn(fmt, "= \t%");
+ if (!fmt[i]) GOTO_ERROR;
+
+ fmt[i] = 0;
+
+ if (bmesh_name_to_slotcode_check(def, fmt) < 0) GOTO_ERROR;
+
+ BLI_strncpy(slotname, fmt, sizeof(slotname));
+
+ state = 0;
+ fmt += i;
+ }
+ else {
+ switch (*fmt) {
+ case ' ':
+ case '\t':
+ case '=':
+ case '%':
+ break;
+ case 'm': {
+ int size, c;
+
+ c = NEXT_CHAR(fmt);
+ fmt++;
+
+ if (c == '3') size = 3;
+ else if (c == '4') size = 4;
+ else GOTO_ERROR;
+
+ BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
+ state = 1;
+ break;
+ }
+ case 'v': {
+ BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
+ state = 1;
+ break;
+ }
+ case 'e': {
+ BMHeader *ele = va_arg(vlist, void *);
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
+ slot->len = 1;
+ *((void **)slot->data.buf) = ele;
+
+ state = 1;
+ break;
+ }
+ case 's': {
+ BMOperator *op2 = va_arg(vlist, void *);
+ const char *slotname2 = va_arg(vlist, char *);
+
+ BMO_slot_copy(op2, op, slotname2, slotname);
+ state = 1;
+ break;
+ }
+ case 'i':
+ case 'd':
+ BMO_slot_int_set(op, slotname, va_arg(vlist, int));
+ state = 1;
+ break;
+ case 'p':
+ BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
+ state = 1;
+ break;
+ case 'f':
+ case 'h':
+ case 'a':
+ type = *fmt;
+
+ if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\t' || NEXT_CHAR(fmt) == '\0') {
+ BMO_slot_float_set(op, slotname, va_arg(vlist, double));
+ }
+ else {
+ ret = 0;
+ stop = 0;
+ while (1) {
+ switch (NEXT_CHAR(fmt)) {
+ case 'f': ret |= BM_FACE; break;
+ case 'e': ret |= BM_EDGE; break;
+ case 'v': ret |= BM_VERT; break;
+ default:
+ stop = 1;
+ break;
+ }
+ if (stop) {
+ break;
+ }
+
+ fmt++;
+ }
+
+ if (type == 'h') {
+ BMO_slot_from_hflag(bm, op, slotname, va_arg(vlist, int), ret);
+ }
+ else if (type == 'a') {
+ BMO_slot_from_all(bm, op, slotname, ret);
+ }
+ else {
+ BMO_slot_from_flag(bm, op, slotname, va_arg(vlist, int), ret);
+ }
+ }
+
+ state = 1;
+ break;
+ default:
+ fprintf(stderr,
+ "%s: unrecognized bmop format char: %c, %d in '%s'\n",
+ __func__, *fmt, (int)(fmt - ofmt), ofmt);
+ break;
+ }
+ }
+ fmt++;
+ }
+
+ MEM_freeN(ofmt);
+ return TRUE;
+error:
+
+ /* non urgent todo - explain exactly what is failing */
+ fprintf(stderr,
+ "%s: error parsing formatting string, %d in '%s'\n see - %s:%d\n",
+ __func__, (int)(fmt - ofmt), _fmt, __FILE__, lineno);
+ MEM_freeN(ofmt);
+
+ BMO_op_finish(bm, op);
+ return FALSE;
+
+#undef GOTO_ERROR
+
+}
+
+
+int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
+{
+ va_list list;
+
+ va_start(list, fmt);
+ if (!BMO_op_vinitf(bm, op, fmt, list)) {
+ printf("%s: failed\n", __func__);
+ va_end(list);
+ return FALSE;
+ }
+ va_end(list);
+
+ return TRUE;
+}
+
+int BMO_op_callf(BMesh *bm, const char *fmt, ...)
+{
+ va_list list;
+ BMOperator op;
+
+ va_start(list, fmt);
+ if (!BMO_op_vinitf(bm, &op, fmt, list)) {
+ printf("%s: failed, format is:\n \"%s\"\n", __func__, fmt);
+ va_end(list);
+ return FALSE;
+ }
+
+ BMO_op_exec(bm, &op);
+ BMO_op_finish(bm, &op);
+
+ va_end(list);
+ return TRUE;
+}