diff options
Diffstat (limited to 'source/blender/bmesh/intern/bmesh_operators.c')
-rw-r--r-- | source/blender/bmesh/intern/bmesh_operators.c | 1383 |
1 files changed, 1383 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..9a5193f4811 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -0,0 +1,1383 @@ +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_mempool.h" +#include "BLI_blenlib.h" +#include "BLI_array.h" + +#include "bmesh.h" +#include "bmesh_private.h" +#include "stdarg.h" + +#include <string.h> + +/*forward declarations*/ +static void alloc_flag_layer(BMesh *bm); +static void free_flag_layer(BMesh *bm); +static void clear_flag_layer(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 *bmop_error_messages[] = { + 0, + "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 BMOP_OPSLOT_TYPEINFO[] = { + 0, + sizeof(int), + sizeof(float), + sizeof(void*), + 0, /* unused */ + 0, /* unused */ + 0, /* unused */ + sizeof(void*), /* pointer buffer */ + sizeof(element_mapping) +}; + +/* Dummy slot so there is something to return when slot name lookup fails */ +static BMOpSlot BMOpEmptySlot = { 0 }; + +void BMO_Set_OpFlag(BMesh *UNUSED(bm), BMOperator *op, int flag) +{ + op->flag |= flag; +} + +void BMO_Clear_OpFlag(BMesh *UNUSED(bm), BMOperator *op, int flag) +{ + op->flag &= ~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) + alloc_flag_layer(bm); + else + clear_flag_layer(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) + free_flag_layer(bm); + + bm->stackdepth--; +} + +/* + * BMESH OPSTACK INIT OP + * + * Initializes an operator structure + * to a certain type + * +*/ + +void BMO_Init_Op(BMOperator *op, const char *opname) +{ + int i, opcode = bmesh_opname_to_opcode(opname); + + 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_Exec_Op(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_Finish_Op(BMesh *UNUSED(bm), BMOperator *op) +{ + BMOpSlot *slot; + int i; + + for (i=0; opdefines[op->type]->slottypes[i].type; i++) { + slot = &op->slots[i]; + if (slot->slottype == BMOP_OPSLOT_MAPPING) { + if (slot->data.ghash) + BLI_ghash_free(slot->data.ghash, NULL, NULL); + } + } + + BLI_memarena_free(op->arena); +} + +/* + * BMESH OPSTACK HAS SLOT + * + * Returns 1 if the named slot exists on the given operator, + * otherwise returns 0. + * +*/ + +int BMO_HasSlot(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_GetSlot(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_CopySlot(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst) +{ + BMOpSlot *source_slot = BMO_GetSlot(source_op, src); + BMOpSlot *dest_slot = BMO_GetSlot(dest_op, dst); + + if(source_slot == dest_slot) + return; + + if(source_slot->slottype != dest_slot->slottype) + return; + + if (dest_slot->slottype > BMOP_OPSLOT_VEC) { + if (dest_slot->slottype != BMOP_OPSLOT_MAPPING) { + /*do buffer copy*/ + dest_slot->data.buf = NULL; + dest_slot->len = source_slot->len; + if(dest_slot->len){ + dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len); + memcpy(dest_slot->data.buf, source_slot->data.buf, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len); + } + } else { + GHashIterator it; + element_mapping *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_Set_Float(BMOperator *op, const char *slotname, float f) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_FLT) ) + return; + + slot->data.f = f; +} + +void BMO_Set_Int(BMOperator *op, const char *slotname, int i) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_INT) ) + return; + + slot->data.i = i; +} + +/*only supports square mats*/ +void BMO_Set_Mat(struct BMOperator *op, const char *slotname, float *mat, int size) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_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); + return; + } +} + +void BMO_Get_Mat4(struct BMOperator *op, const char *slotname, float mat[4][4]) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_MAT) ) + return; + + memcpy(mat, slot->data.p, sizeof(float)*4*4); +} + +void BMO_Get_Mat3(struct BMOperator *op, const char *slotname, float mat[3][3]) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_MAT) ) + return; + + copy_m3_m4(mat, slot->data.p); +} + +void BMO_Set_Pnt(BMOperator *op, const char *slotname, void *p) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_PNT) ) + return; + + slot->data.p = p; +} + +void BMO_Set_Vec(BMOperator *op, const char *slotname, float *vec) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_VEC) ) + return; + + copy_v3_v3(slot->data.vec, vec); +} + + +float BMO_Get_Float(BMOperator *op, const char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_FLT) ) + return 0.0f; + + return slot->data.f; +} + +int BMO_Get_Int(BMOperator *op, const char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_INT) ) + return 0; + + return slot->data.i; +} + + +void *BMO_Get_Pnt(BMOperator *op, const char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_PNT) ) + return NULL; + + return slot->data.p; +} + +void BMO_Get_Vec(BMOperator *op, const char *slotname, float *vec_out) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_VEC) ) + return; + + copy_v3_v3(vec_out, slot->data.vec); +} + +/* + * BMO_COUNTFLAG + * + * Counts the number of elements of a certain type that + * have a specific flag set. + * +*/ + +int BMO_CountFlag(BMesh *bm, int flag, int type) +{ + BMIter elements; + BMHeader *e; + int count = 0; + + if(type & BM_VERT){ + for(e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)){ + if(BMO_TestFlag(bm, e, flag)) + count++; + } + } + if(type & BM_EDGE){ + for(e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)){ + if(BMO_TestFlag(bm, e, flag)) + count++; + } + } + if(type & BM_FACE){ + for(e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)){ + if(BMO_TestFlag(bm, e, flag)) + count++; + } + } + + return count; +} + +void BMO_Clear_Flag_All(BMesh *bm, BMOperator *UNUSED(op), int type, int flag) { + BMIter iter; + BMHeader *ele; + int i=0, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH}; + + for (i=0; i<3; i++) { + if (i==0 && !(type & BM_VERT)) + continue; + if (i==1 && !(type & BM_EDGE)) + continue; + if (i==2 && !(type & BM_FACE)) + continue; + + BM_ITER(ele, &iter, bm, types[i], NULL) { + BMO_ClearFlag(bm, ele, flag); + } + } +} + +int BMO_CountSlotBuf(struct BMesh *UNUSED(bm), struct BMOperator *op, const char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*check if its actually a buffer*/ + if( !(slot->slottype > BMOP_OPSLOT_VEC) ) + return 0; + + return slot->len; +} + +int BMO_CountSlotMap(BMesh *UNUSED(bm), BMOperator *op, const char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*check if its actually a buffer*/ + if( !(slot->slottype == BMOP_OPSLOT_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; + + /*check if its actually a buffer*/ + if( !(slot->slottype > BMOP_OPSLOT_VEC) ) + return NULL; + + if (slot->flag & BMOS_DYNAMIC_ARRAY) { + if (slot->len >= slot->size) { + slot->size = (slot->size+1+totadd)*2; + + tmp = slot->data.buf; + slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size, "opslot dynamic array"); + memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size); + MEM_freeN(tmp); + } + + slot->len += totadd; + } else { + slot->flag |= BMOS_DYNAMIC_ARRAY; + slot->len += totadd; + slot->size = slot->len+2; + tmp = slot->data.buf; + slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len, "opslot dynamic array"); + memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len); + } + + return slot->data.buf; +} +#endif + +void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op, + const char *slotname, int flag) +{ + GHashIterator it; + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader *ele; + + /*sanity check*/ + if (slot->slottype != BMOP_OPSLOT_MAPPING) return; + if (!slot->data.ghash) return; + + BLI_ghashIterator_init(&it, slot->data.ghash); + for ( ; (ele=BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) { + BMO_SetFlag(bm, ele, flag); + } +} + +static void *alloc_slot_buffer(BMOperator *op, const char *slotname, int len){ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*check if its actually a buffer*/ + if( !(slot->slottype > BMOP_OPSLOT_VEC) ) + return NULL; + + slot->len = len; + if(len) + slot->data.buf = BLI_memarena_alloc(op->arena, BMOP_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_All_To_Slot(BMesh *bm, BMOperator *op, const char *slotname, int type) +{ + BMIter elements; + BMHeader *e; + BMOpSlot *output = BMO_GetSlot(op, slotname); + int totelement=0, i=0; + + if (type & BM_VERT) totelement += bm->totvert; + if (type & BM_EDGE) totelement += bm->totedge; + if (type & BM_FACE) totelement += bm->totface; + + if(totelement){ + alloc_slot_buffer(op, slotname, totelement); + + if (type & BM_VERT) { + for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + + if (type & BM_EDGE) { + for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + + if (type & BM_FACE) { + for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_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_HeaderFlag_To_Slot(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type) +{ + BMIter elements; + BMHeader *e; + BMOpSlot *output = BMO_GetSlot(op, slotname); + int totelement=0, i=0; + + totelement = BM_CountFlag(bm, type, flag, 1); + + if(totelement){ + alloc_slot_buffer(op, slotname, totelement); + + if (type & BM_VERT) { + for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, flag)) { + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + + if (type & BM_EDGE) { + for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, flag)) { + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + + if (type & BM_FACE) { + for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, flag)) { + ((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_Flag_To_Slot(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type) +{ + BMIter elements; + BMHeader *e; + BMOpSlot *output = BMO_GetSlot(op, slotname); + int totelement = BMO_CountFlag(bm, flag, type), i=0; + + if(totelement){ + alloc_slot_buffer(op, slotname, totelement); + + if (type & BM_VERT) { + for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(BMO_TestFlag(bm, e, flag)){ + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + + if (type & BM_EDGE) { + for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(BMO_TestFlag(bm, e, flag)){ + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + + if (type & BM_FACE) { + for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(BMO_TestFlag(bm, e, flag)){ + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + } else { + output->len = 0; + } +} + +/* + * + * BMO_FLAG_BUFFER + * + * Header Flags elements in a slots buffer, automatically + * using the selection API where appropriate. + * +*/ + +void BMO_HeaderFlag_Buffer(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader **data = slot->data.p; + int i; + + for(i = 0; i < slot->len; i++) { + if (!(type & data[i]->type)) + continue; + + if (flag & BM_SELECT) { + BM_Select(bm, data[i], 1); + } + BM_SetHFlag(data[i], flag); + } +} + +/* + * + * BMO_FLAG_BUFFER + * + * Removes flags from elements in a slots buffer, automatically + * using the selection API where appropriate. + * +*/ + +void BMO_UnHeaderFlag_Buffer(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader **data = slot->data.p; + int i; + + for(i = 0; i < slot->len; i++) { + if (!(type & data[i]->type)) + continue; + + if (flag & BM_SELECT) + BM_Select(bm, data[i], 0); + BM_ClearHFlag(data[i], flag); + } +} + +int BMO_Vert_CountEdgeFlags(BMesh *bm, BMVert *v, int toolflag) +{ + BMEdge *curedge; + int i, len=0, count=0; + + if(v->e) { + len = bmesh_disk_count(v); + + for(i = 0, curedge=v->e; i<len; i++){ + if (BMO_TestFlag(bm, curedge, toolflag)) + count++; + curedge = bmesh_disk_nextedge(curedge, v); + } + } + + return count; +} + +/* + * + * BMO_FLAG_BUFFER + * + * Flags elements in a slots buffer + * +*/ + +void BMO_Flag_Buffer(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader **data = slot->data.p; + int i; + + for(i = 0; i < slot->len; i++) { + if (!(type & data[i]->type)) + continue; + + BMO_SetFlag(bm, data[i], flag); + } +} + +/* + * + * BMO_FLAG_BUFFER + * + * Removes flags from elements in a slots buffer + * +*/ + +void BMO_Unflag_Buffer(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader **data = slot->data.p; + int i; + + for(i = 0; i < slot->len; i++) { + if (!(type & data[i]->type)) + continue; + + BMO_ClearFlag(bm, data[i], flag); + } +} + + +/* + * + * 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 alloc_flag_layer(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + BLI_mempool *oldpool = bm->toolflagpool; /*old flag pool*/ + void *oldflags; + + bm->totflags++; + + /*allocate new flag pool*/ + bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, 0, 0); + + /*now go through and memcpy all the flags. Loops don't get a flag layer at this time...*/ + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){ + oldflags = v->head.flags; + v->head.flags = BLI_mempool_calloc(bm->toolflagpool); + memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*(bm->totflags-1)); + } + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ + oldflags = e->head.flags; + e->head.flags = BLI_mempool_calloc(bm->toolflagpool); + memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*(bm->totflags-1)); + } + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){ + oldflags = f->head.flags; + f->head.flags = BLI_mempool_calloc(bm->toolflagpool); + memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*(bm->totflags-1)); + } + + BLI_mempool_destroy(oldpool); +} + +static void free_flag_layer(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + BLI_mempool *oldpool = bm->toolflagpool; + void *oldflags; + + /*de-increment the totflags first...*/ + bm->totflags--; + /*allocate new flag pool*/ + bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, 1, 0); + + /*now go through and memcpy all the flags*/ + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){ + oldflags = v->head.flags; + v->head.flags = BLI_mempool_calloc(bm->toolflagpool); + memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); /*correct?*/ + } + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ + oldflags = e->head.flags; + e->head.flags = BLI_mempool_calloc(bm->toolflagpool); + memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); + } + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){ + oldflags = f->head.flags; + f->head.flags = BLI_mempool_calloc(bm->toolflagpool); + memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); + } + + BLI_mempool_destroy(oldpool); +} + +static void clear_flag_layer(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + + /*now go through and memcpy all the flags*/ + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){ + memset(v->head.flags+(bm->totflags-1), 0, sizeof(BMFlagLayer)); + } + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ + memset(e->head.flags+(bm->totflags-1), 0, sizeof(BMFlagLayer)); + } + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){ + memset(f->head.flags+(bm->totflags-1), 0, sizeof(BMFlagLayer)); + } +} + +void *BMO_FirstElem(BMOperator *op, const char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + if (slot->slottype != BMOP_OPSLOT_ELEMENT_BUF) + return NULL; + + return slot->data.buf ? *(void**)slot->data.buf : NULL; +} + +void *BMO_IterNew(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op, + const char *slotname, int restrictmask) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + memset(iter, 0, sizeof(BMOIter)); + + iter->slot = slot; + iter->cur = 0; + iter->restrictmask = restrictmask; + + if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) { + if (iter->slot->data.ghash) + BLI_ghashIterator_init(&iter->giter, slot->data.ghash); + else return NULL; + } + + return BMO_IterStep(iter); +} + +void *BMO_IterStep(BMOIter *iter) +{ + if (iter->slot->slottype == BMOP_OPSLOT_ELEMENT_BUF) { + BMHeader *h; + + if (iter->cur >= iter->slot->len) return NULL; + + h = ((void**)iter->slot->data.buf)[iter->cur++]; + while (!(iter->restrictmask & h->type)) { + if (iter->cur >= iter->slot->len) return NULL; + h = ((void**)iter->slot->data.buf)[iter->cur++]; + } + + return h; + } else if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) { + struct element_mapping *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 mappings*/ +void *BMO_IterMapVal(BMOIter *iter) +{ + return iter->val; +} + +void *BMO_IterMapValp(BMOIter *iter) +{ + return *((void**)iter->val); +} + +float BMO_IterMapValf(BMOIter *iter) +{ + return *((float*)iter->val); +} + +/*error system*/ +typedef struct bmop_error { + struct bmop_error *next, *prev; + int errorcode; + BMOperator *op; + const char *msg; +} bmop_error; + +void BMO_ClearStack(BMesh *bm) +{ + while (BMO_PopError(bm, NULL, NULL)); +} + +void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, const char *msg) +{ + bmop_error *err = MEM_callocN(sizeof(bmop_error), "bmop_error"); + + err->errorcode = errcode; + if (!msg) msg = bmop_error_messages[errcode]; + err->msg = msg; + err->op = owner; + + BLI_addhead(&bm->errorstack, err); +} + +int BMO_HasError(BMesh *bm) +{ + return bm->errorstack.first != NULL; +} + +/*returns error code or 0 if no error*/ +int BMO_GetError(BMesh *bm, const char **msg, BMOperator **op) +{ + bmop_error *err = bm->errorstack.first; + if (!err) return 0; + + if (msg) *msg = err->msg; + if (op) *op = err->op; + + return err->errorcode; +} + +int BMO_PopError(BMesh *bm, const char **msg, BMOperator **op) +{ + int errorcode = BMO_GetError(bm, msg, op); + + if (errorcode) { + bmop_error *err = bm->errorstack.first; + + BLI_remlink(&bm->errorstack, bm->errorstack.first); + MEM_freeN(err); + } + + return errorcode; +} + +/* +typedef struct bflag { + const char *str; + int flag; +} bflag; + +#define b(f) {#f, f}, +static const char *bmesh_flags = { + b(BM_SELECT); + b(BM_SEAM); + b(BM_FGON); + b(BM_HIDDEN); + b(BM_SHARP); + b(BM_SMOOTH); + {NULL, 0}; +}; + +int bmesh_str_to_flag(const char *str) +{ + int i; + + while (bmesh_flags[i]->name) { + if (!strcmp(bmesh_flags[i]->name, str)) + return bmesh_flags[i]->flag; + } + + return -1; +} +*/ + +//example: +//BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_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 nextc(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 (!strcmp(name, def->slottypes[i].name)) 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)) break; + } + + if (i == bmesh_total_ops) { + fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname); + return 0; + } + + return i; +} + +int BMO_VInitOpf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist) +{ + BMOpDefine *def; + char *opname, *ofmt, *fmt = (char*)_fmt; + char slotname[64] = {0}; + int i /*, n=strlen(fmt) */, stop /*, slotcode = -1 */, ret, type, state, c; + int noslot=0; + + /*we muck around in here, so dup it*/ + fmt = ofmt = strdup(fmt); + + /*find operator name*/ + i = strcspn(fmt, " \t"); + + opname = fmt; + if (!opname[i]) noslot = 1; + opname[i] = 0; + + fmt += i + (noslot ? 0 : 1); + + for (i=0; i<bmesh_total_ops; i++) { + if (!strcmp(opname, opdefines[i]->name)) break; + } + + if (i == bmesh_total_ops) return 0; + + BMO_Init_Op(op, opname); + def = opdefines[i]; + + i = 0; + state = 1; //0: not inside slotcode name, 1: inside slotcode name + c = 0; + + while (*fmt) { + if (state) { + /*jump past leading whitespace*/ + i = strspn(fmt, " \t"); + fmt += i; + + /*ignore trailing whitespace*/ + 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; + + strcpy(slotname, fmt); + + state = 0; + fmt += i; + } else { + switch (*fmt) { + case ' ': + case '\t': + case '=': + case '%': + break; + case 'm': { + int size, c; + + c = nextc(fmt); + fmt++; + + if (c == '3') size = 3; + else if (c == '4') size = 4; + else goto error; + + BMO_Set_Mat(op, slotname, va_arg(vlist, void*), size); + state = 1; + break; + } + case 'v': { + BMO_Set_Vec(op, slotname, va_arg(vlist, float*)); + state = 1; + break; + } + case 'e': { + BMHeader *ele = va_arg(vlist, void*); + BMOpSlot *slot = BMO_GetSlot(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_CopySlot(op2, op, slotname2, slotname); + state = 1; + break; + } + case 'i': + case 'd': + BMO_Set_Int(op, slotname, va_arg(vlist, int)); + state = 1; + break; + case 'p': + BMO_Set_Pnt(op, slotname, va_arg(vlist, void*)); + state = 1; + break; + case 'f': + case 'h': + case 'a': + type = *fmt; + + if (nextc(fmt) == ' ' || nextc(fmt) == '\t' || + nextc(fmt)==0) + { + BMO_Set_Float(op,slotname,va_arg(vlist,double)); + } else { + ret = 0; + stop = 0; + while (1) { + switch (nextc(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_HeaderFlag_To_Slot(bm, op, + slotname, va_arg(vlist, int), ret); + else if (type == 'a') + BMO_All_To_Slot(bm, op, slotname, ret); + else + BMO_Flag_To_Slot(bm, op, slotname, + va_arg(vlist, int), ret); + } + + state = 1; + break; + default: + printf("unrecognized bmop format char: %c\n", *fmt); + break; + } + } + fmt++; + } + + free(ofmt); + return 1; +error: + BMO_Finish_Op(bm, op); + return 0; +} + + +int BMO_InitOpf(BMesh *bm, BMOperator *op, const char *fmt, ...) { + va_list list; + + va_start(list, fmt); + if (!BMO_VInitOpf(bm, op, fmt, list)) { + printf("BMO_InitOpf failed\n"); + va_end(list); + return 0; + } + va_end(list); + + return 1; +} + +int BMO_CallOpf(BMesh *bm, const char *fmt, ...) { + va_list list; + BMOperator op; + + va_start(list, fmt); + if (!BMO_VInitOpf(bm, &op, fmt, list)) { + printf("BMO_CallOpf failed, format is:\n \"%s\"\n", fmt); + va_end(list); + return 0; + } + + BMO_Exec_Op(bm, &op); + BMO_Finish_Op(bm, &op); + + va_end(list); + return 1; +} + +/* + * BMO_TOGGLEFLAG + * + * Toggles a flag for a certain element + * +*/ +#ifdef BMO_ToggleFlag +#undef BMO_ToggleFlag +#endif +static void BMO_ToggleFlag(BMesh *bm, void *element, int flag) +{ + BMHeader *head = element; + head->flags[bm->stackdepth-1].f ^= flag; +} + +/* + * BMO_SETFLAG + * + * Sets a flag for a certain element + * +*/ +#ifdef BMO_SetFlag +#undef BMO_SetFlag +#endif +static void BMO_SetFlag(BMesh *bm, void *element, int flag) +{ + BMHeader *head = element; + head->flags[bm->stackdepth-1].f |= flag; +} + +/* + * BMO_CLEARFLAG + * + * Clears a specific flag from a given element + * +*/ + +#ifdef BMO_ClearFlag +#undef BMO_ClearFlag +#endif +static void BMO_ClearFlag(BMesh *bm, void *element, int flag) +{ + BMHeader *head = element; + head->flags[bm->stackdepth-1].f &= ~flag; +} + +/* + * BMO_TESTFLAG + * + * Tests whether or not a flag is set for a specific element + * + * +*/ + +#ifdef BMO_TestFlag +#undef BMO_TestFlag +#endif +static int BMO_TestFlag(BMesh *bm, void *element, int flag) +{ + BMHeader *head = element; + if(head->flags[bm->stackdepth-1].f & flag) + return 1; + return 0; +} |