diff options
Diffstat (limited to 'source/blender/bmesh/bmesh_operator_api.h')
-rw-r--r-- | source/blender/bmesh/bmesh_operator_api.h | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/source/blender/bmesh/bmesh_operator_api.h b/source/blender/bmesh/bmesh_operator_api.h new file mode 100644 index 00000000000..5122391d9d5 --- /dev/null +++ b/source/blender/bmesh/bmesh_operator_api.h @@ -0,0 +1,512 @@ +#ifndef _BMESH_OPERATOR_API_H +#define _BMESH_OPERATOR_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_memarena.h" +#include "BLI_ghash.h" + +#include "BKE_utildefines.h" + +#include <stdarg.h> +#include <string.h> /* for memcpy */ + +/* +operators represent logical, executable mesh modules. all topological +operations involving a bmesh has to go through them. + +operators are nested, as are tool flags, which are private to an operator +when it's executed. tool flags are allocated in layers, one per operator +execution, and are used for all internal flagging a tool needs to do. + +each operator has a series of "slots," which can be of the following types: +* simple numerical types +* arrays of elements (e.g. arrays of faces). +* hash mappings. + +each slot is identified by a slot code, as are each operator. +operators, and their slots, are defined in bmesh_opdefines.c (with their +execution functions prototyped in bmesh_operators_private.h), with all their +operator code and slot codes defined in bmesh_operators.h. see +bmesh_opdefines.c and the BMOpDefine struct for how to define new operators. + +in general, operators are fed arrays of elements, created using either +BM_HeaderFlag_To_Slot or BM_Flag_To_Slot (or through one of the format +specifyers in BMO_CallOpf or BMO_InitOpf). Note that multiple element +types (e.g. faces and edges) can be fed to the same slot array. Operators +act on this data, and possibly spit out data into output slots. + +some notes: +* operators should never read from header flags (e.g. element->head.flag). for + example, if you want an operator to only operate on selected faces, you + should use BM_HeaderFlag_To_Slot to put the selected elements into a slot. +* when you read from an element slot array or mapping, you can either tool-flag + all the elements in it, or read them using an iterator APi (which is + semantically similar to the iterator api in bmesh_iterators.h). +*/ + +struct GHashIterator; + +/*slot type arrays are terminated by the last member + having a slot type of 0.*/ +#define BMOP_OPSLOT_SENTINEL 0 +#define BMOP_OPSLOT_INT 1 +#define BMOP_OPSLOT_FLT 2 +#define BMOP_OPSLOT_PNT 3 +#define BMOP_OPSLOT_MAT 4 +#define BMOP_OPSLOT_VEC 7 + +/*after BMOP_OPSLOT_VEC, everything is + + dynamically allocated arrays. we + leave a space in the identifiers + for future growth. + + */ +//it's very important this remain a power of two +#define BMOP_OPSLOT_ELEMENT_BUF 8 +#define BMOP_OPSLOT_MAPPING 9 +#define BMOP_OPSLOT_TYPES 10 + +/*please ignore all these structures, don't touch them in tool code, except + for when your defining an operator with BMOpDefine.*/ + +typedef struct BMOpSlot{ + int slottype; + int len; + int flag; + int index; /*index within slot array*/ + union { + int i; + float f; + void *p; + float vec[3]; + void *buf; + GHash *ghash; + } data; +} BMOpSlot; + +#define BMOP_MAX_SLOTS 16 /*way more than probably needed*/ + +#ifdef slots +#undef slots +#endif + +typedef struct BMOperator { + int type; + int slottype; + int needflag; + int flag; + struct BMOpSlot slots[BMOP_MAX_SLOTS]; + void (*exec)(struct BMesh *bm, struct BMOperator *op); + MemArena *arena; +} BMOperator; + +#define MAX_SLOTNAME 32 + +typedef struct slottype { + int type; + char name[MAX_SLOTNAME]; +} slottype; + +typedef struct BMOpDefine { + const char *name; + slottype slottypes[BMOP_MAX_SLOTS]; + void (*exec)(BMesh *bm, BMOperator *op); + int flag; +} BMOpDefine; + +/*BMOpDefine->flag*/ +#define BMOP_UNTAN_MULTIRES 1 /*switch from multires tangent space to absolute coordinates*/ + + +/*ensures consistent normals before operator execution, + restoring the original ones windings/normals afterwards. + keep in mind, this won't work if the input mesh isn't + manifold.*/ +#define BMOP_RATIONALIZE_NORMALS 2 + +/*------------- Operator API --------------*/ + +/*data types that use pointers (arrays, etc) should never + have it set directly. and never use BMO_Set_Pnt to + pass in a list of edges or any arrays, really.*/ + +void BMO_Init_Op(struct BMesh *bm, struct BMOperator *op, const char *opname); + +/*executes an operator, pushing and popping a new tool flag + layer as appropriate.*/ +void BMO_Exec_Op(struct BMesh *bm, struct BMOperator *op); + +/*finishes an operator (though note the operator's tool flag is removed + after it finishes executing in BMO_Exec_Op).*/ +void BMO_Finish_Op(struct BMesh *bm, struct BMOperator *op); + + +/*tool flag API. never, ever ever should tool code put junk in + header flags (element->head.flag), nor should they use + element->head.eflag1/eflag2. instead, use this api to set + flags. + + if you need to store a value per element, use a + ghash or a mapping slot to do it.*/ +/*flags 15 and 16 (1<<14 and 1<<15) are reserved for bmesh api use*/ +#define BMO_TestFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f & (flag)) +#define BMO_SetFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f |= (flag)) +#define BMO_ClearFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f &= ~(flag)) +#define BMO_ToggleFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f ^= (flag)) + +/*profiling showed a significant amount of time spent in BMO_TestFlag +void BMO_SetFlag(struct BMesh *bm, void *element, int flag); +void BMO_ClearFlag(struct BMesh *bm, void *element, int flag); +int BMO_TestFlag(struct BMesh *bm, void *element, int flag);*/ + +/*count the number of elements with a specific flag. type + can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE.*/ +int BMO_CountFlag(struct BMesh *bm, int flag, const char htype); + +/*---------formatted operator initialization/execution-----------*/ +/* + this system is used to execute or initialize an operator, + using a formatted-string system. + + for example, BMO_CallOpf(bm, "del geom=%hf context=%d", BM_SELECT, DEL_FACES); + . . .will execute the delete operator, feeding in selected faces, deleting them. + + the basic format for the format string is: + [operatorname] [slotname]=%[code] [slotname]=%[code] + + as in printf, you pass in one additional argument to the function + for every code. + + the formatting codes are: + %d - put int in slot + %f - put float in slot + %p - put pointer in slot + %h[f/e/v] - put elements with a header flag in slot. + the letters after %h define which element types to use, + so e.g. %hf will do faces, %hfe will do faces and edges, + %hv will do verts, etc. must pass in at least one + element type letter. + %f[f/e/v] - same as %h, except it deals with tool flags instead of + header flags. + %a[f/e/v] - pass all elements (of types specified by f/e/v) to the + slot. + %e - pass in a single element. + %v - pointer to a float vector of length 3. + %m[3/4] - matrix, 3/4 refers to the matrix size, 3 or 4. the + corrusponding argument must be a pointer to + a float matrix. + %s - copy a slot from another op, instead of mapping to one + argument, it maps to two, a pointer to an operator and + a slot name. +*/ +void BMO_push(BMesh *bm, BMOperator *op); +void BMO_pop(BMesh *bm); + +/*executes an operator*/ +int BMO_CallOpf(BMesh *bm, const char *fmt, ...); + +/*initializes, but doesn't execute an operator. this is so you can + gain access to the outputs of the operator. note that you have + to execute/finitsh (BMO_Exec_Op and BMO_Finish_Op) yourself.*/ +int BMO_InitOpf(BMesh *bm, BMOperator *op, const char *fmt, ...); + +/*va_list version, used to implement the above two functions, + plus EDBM_CallOpf in bmeshutils.c.*/ +int BMO_VInitOpf(BMesh *bm, BMOperator *op, const char *fmt, va_list vlist); + +/*test whether a named slot exists*/ +int BMO_HasSlot(struct BMOperator *op, const char *slotname); + +/*get a pointer to a slot. this may be removed layer on from the public API.*/ +BMOpSlot *BMO_GetSlot(struct BMOperator *op, const char *slotname); + +/*copies the data of a slot from one operator to another. src and dst are the + source/destination slot codes, respectively.*/ +void BMO_CopySlot(struct BMOperator *source_op, struct BMOperator *dest_op, + const char *src, const char *dst); + +/*remove tool flagged elements*/ +void BM_remove_tagged_faces(struct BMesh *bm, int flag); +void BM_remove_tagged_edges(struct BMesh *bm, int flag); +void BM_remove_tagged_verts(struct BMesh *bm, int flag); + +void BMO_Set_OpFlag(struct BMesh *bm, struct BMOperator *op, int flag); +void BMO_Clear_OpFlag(struct BMesh *bm, struct BMOperator *op, int flag); + +void BMO_Set_Float(struct BMOperator *op, const char *slotname, float f); +float BMO_Get_Float(BMOperator *op, const char *slotname); +void BMO_Set_Int(struct BMOperator *op, const char *slotname, int i); +int BMO_Get_Int(BMOperator *op, const char *slotname); + +/*don't pass in arrays that are supposed to map to elements this way. + + so, e.g. passing in list of floats per element in another slot is bad. + passing in, e.g. pointer to an editmesh for the conversion operator is fine + though.*/ +void BMO_Set_Pnt(struct BMOperator *op, const char *slotname, void *p); +void *BMO_Get_Pnt(BMOperator *op, const char *slotname); +void BMO_Set_Vec(struct BMOperator *op, const char *slotname, float *vec); +void BMO_Get_Vec(BMOperator *op, const char *slotname, float *vec_out); + +/*only supports square mats*/ +/*size must be 3 or 4; this api is meant only for transformation matrices. + note that internally the matrix is stored in 4x4 form, and it's safe to + call whichever BMO_Get_Mat* function you want.*/ +void BMO_Set_Mat(struct BMOperator *op, const char *slotname, float *mat, int size); +void BMO_Get_Mat4(struct BMOperator *op, const char *slotname, float mat[4][4]); +void BMO_Get_Mat3(struct BMOperator *op, const char *slotname, float mat[3][3]); + +void BMO_Clear_Flag_All(BMesh *bm, BMOperator *op, const char htype, int flag); + +/*puts every element of type type (which is a bitmask) with tool flag flag, + into a slot.*/ +void BMO_Flag_To_Slot(struct BMesh *bm, struct BMOperator *op, const char *slotname, const int flag, const char htype); + +/*tool-flags all elements inside an element slot array with flag flag.*/ +void BMO_Flag_Buffer(struct BMesh *bm, struct BMOperator *op, const char *slotname, const int hflag, const char htype); +/*clears tool-flag flag from all elements inside a slot array.*/ +void BMO_Unflag_Buffer(struct BMesh *bm, struct BMOperator *op, const char *slotname, const int flag, const char htype); + +/*tool-flags all elements inside an element slot array with flag flag.*/ +void BMO_HeaderFlag_Buffer(struct BMesh *bm, struct BMOperator *op, const char *slotname, const char hflag, const char htype); +/*clears tool-flag flag from all elements inside a slot array.*/ +void BMO_UnHeaderFlag_Buffer(struct BMesh *bm, struct BMOperator *op, const char *slotname, const char hflag, const char htype); + +/*puts every element of type type (which is a bitmask) with header flag + flag, into a slot. note: ignores hidden elements (e.g. elements with + header flag BM_HIDDEN set).*/ +void BMO_HeaderFlag_To_Slot(struct BMesh *bm, struct BMOperator *op, const char *slotname, const char hflag, const char htype); + +/*counts number of elements inside a slot array.*/ +int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, const char *slotname); +int BMO_CountSlotMap(struct BMesh *bm, struct BMOperator *op, const char *slotname); + +/*Counts the number of edges with tool flag toolflag around + v*/ +int BMO_Vert_CountEdgeFlags(BMesh *bm, BMVert *v, int toolflag); + +/*inserts a key/value mapping into a mapping slot. note that it copies the + value, it doesn't store a reference to it.*/ +//BM_INLINE void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, const char *slotname, + //void *element, void *data, int len); + +/*inserts a key/float mapping pair into a mapping slot.*/ +//BM_INLINE void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, const char *slotname, + //void *element, float val); + +//returns 1 if the specified pointer is in the map. +//BM_INLINE int BMO_InMap(BMesh *bm, BMOperator *op, const char *slotname, void *element); + +/*returns a point to the value of a specific key.*/ +//BM_INLINE void *BMO_Get_MapData(BMesh *bm, BMOperator *op, const char *slotname, void *element); + +/*returns the float part of a key/float pair.*/ +//BM_INLINE float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, const char *slotname, void *element); + +/*flags all elements in a mapping. note that the mapping must only have + bmesh elements in it.*/ +void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op, + const char *slotname, int flag); + +/*pointer versoins of BMO_Get_MapFloat and BMO_Insert_MapFloat. + + do NOT use these for non-operator-api-allocated memory! instead + use BMO_Get_MapData and BMO_Insert_Mapping, which copies the data.*/ +//BM_INLINE void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, const char *slotname, + //void *key, void *val); +//BM_INLINE void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, const char *slotname, + //void *key); + +/*this part of the API is used to iterate over element buffer or + mapping slots. + + for example, iterating over the faces in a slot is: + + BMOIter oiter; + BMFace *f; + + f = BMO_IterNew(&oiter, bm, some_operator, "slotname", BM_FACE); + for (; f; f=BMO_IterStep(&oiter)) { + /do something with the face + } + + another example, iterating over a mapping: + BMOIter oiter; + void *key; + void *val; + + key = BMO_IterNew(&oiter, bm, some_operator, "slotname", 0); + for (; key; key=BMO_IterStep(&oiter)) { + val = BMO_IterMapVal(&oiter); + //do something with the key/val pair + //note that val is a pointer to the val data, + //whether it's a float, pointer, whatever. + // + // so to get a pointer, for example, use: + // *((void**)BMO_IterMapVal(&oiter)); + //or something like that. + } + + */ + +/*contents of this structure are private, + don't directly access.*/ +typedef struct BMOIter { + BMOpSlot *slot; + int cur; //for arrays + struct GHashIterator giter; + void *val; + char restrictmask; /* bitwise '&' with BMHeader.htype */ +} BMOIter; + +void *BMO_FirstElem(BMOperator *op, const char *slotname); + +/*restrictmask restricts the iteration to certain element types + (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating + over an element buffer (not a mapping).*/ +void *BMO_IterNew(BMOIter *iter, BMesh *bm, BMOperator *op, + const char *slotname, const char restrictmask); +void *BMO_IterStep(BMOIter *iter); + +/*returns a pointer to the key value when iterating over mappings. + remember for pointer maps this will be a pointer to a pointer.*/ +void *BMO_IterMapVal(BMOIter *iter); + +/*use this for pointer mappings*/ +void *BMO_IterMapValp(BMOIter *iter); + +/*use this for float mappings*/ +float BMO_IterMapValf(BMOIter *iter); + +#define BMO_ITER(ele, iter, bm, op, slotname, restrict) \ + ele = BMO_IterNew(iter, bm, op, slotname, restrict); \ + for ( ; ele; ele=BMO_IterStep(iter)) + +/******************* Inlined Functions********************/ +typedef void (*opexec)(struct BMesh *bm, struct BMOperator *op); + +/*mappings map elements to data, which + follows the mapping struct in memory.*/ +typedef struct element_mapping { + BMHeader *element; + int len; +} element_mapping; + +extern const int BMOP_OPSLOT_TYPEINFO[]; + +BM_INLINE void BMO_Insert_Mapping(BMesh *UNUSED(bm), BMOperator *op, const char *slotname, + void *element, void *data, int len) { + element_mapping *mapping; + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*sanity check*/ + if (slot->slottype != BMOP_OPSLOT_MAPPING) return; + + mapping = (element_mapping*) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len); + + mapping->element = (BMHeader*) element; + mapping->len = len; + memcpy(mapping+1, data, len); + + if (!slot->data.ghash) { + slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, + BLI_ghashutil_ptrcmp, "bmesh op"); + } + + BLI_ghash_insert(slot->data.ghash, element, mapping); +} + +BM_INLINE void BMO_Insert_MapInt(BMesh *bm, BMOperator *op, const char *slotname, + void *element, int val) +{ + BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(int)); +} + +BM_INLINE void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, const char *slotname, + void *element, float val) +{ + BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(float)); +} + +BM_INLINE void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, const char *slotname, + void *element, void *val) +{ + BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(void*)); +} + +BM_INLINE int BMO_InMap(BMesh *UNUSED(bm), BMOperator *op, const char *slotname, void *element) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*sanity check*/ + if (slot->slottype != BMOP_OPSLOT_MAPPING) return 0; + if (!slot->data.ghash) return 0; + + return BLI_ghash_haskey(slot->data.ghash, element); +} + +BM_INLINE void *BMO_Get_MapData(BMesh *UNUSED(bm), BMOperator *op, const char *slotname, + void *element) +{ + element_mapping *mapping; + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*sanity check*/ + if (slot->slottype != BMOP_OPSLOT_MAPPING) return NULL; + if (!slot->data.ghash) return NULL; + + mapping = (element_mapping*) BLI_ghash_lookup(slot->data.ghash, element); + + if (!mapping) return NULL; + + return mapping + 1; +} + +BM_INLINE float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, const char *slotname, + void *element) +{ + float *val = (float*) BMO_Get_MapData(bm, op, slotname, element); + if (val) return *val; + + return 0.0f; +} + +BM_INLINE int BMO_Get_MapInt(BMesh *bm, BMOperator *op, const char *slotname, + void *element) +{ + int *val = (int*) BMO_Get_MapData(bm, op, slotname, element); + if (val) return *val; + + return 0; +} + +BM_INLINE void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, const char *slotname, + void *element) +{ + void **val = (void**) BMO_Get_MapData(bm, op, slotname, element); + if (val) return *val; + + return NULL; +} + +BM_INLINE void BMO_SetIndex(BMesh *bm, const void *element, int index) +{ + BMHeader *header = (BMHeader *)element; + header->flags[bm->stackdepth-1].index = index; +} + +BM_INLINE int BMO_GetIndex(BMesh *bm, void *element) +{ + BMHeader *header = (BMHeader *)element; + return header->flags[bm->stackdepth-1].index; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BMESH_OPERATOR_API_H */ |