/* * ***** 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. * * ***** END GPL LICENSE BLOCK ***** */ #ifndef __BMESH_OPERATOR_API_H__ #define __BMESH_OPERATOR_API_H__ /** \file blender/bmesh/intern/bmesh_operator_api.h * \ingroup bmesh */ #ifdef __cplusplus extern "C" { #endif #include "BLI_ghash.h" #include /** * 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 * #BMO_slot_buffer_from_hflag or #BMO_slot_buffer_from_flag * (or through one of the format specifiers in #BMO_op_callf or #BMO_op_initf). * * \note 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. * * \note 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 #BMO_slot_buffer_from_hflag to put the selected elements into a slot. * * \note 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). * * \note only #BMLoop items can't be put into slots as with verts, edges & faces. */ struct GHashIterator; #define BMO_elem_flag_test( bm, ele, oflag) _bmo_elem_flag_test (bm, (ele)->oflags, oflag) #define BMO_elem_flag_test_bool(bm, ele, oflag) _bmo_elem_flag_test_bool(bm, (ele)->oflags, oflag) #define BMO_elem_flag_enable( bm, ele, oflag) _bmo_elem_flag_enable (bm, (ele)->oflags, oflag) #define BMO_elem_flag_disable( bm, ele, oflag) _bmo_elem_flag_disable (bm, (ele)->oflags, oflag) #define BMO_elem_flag_set( bm, ele, oflag, val) _bmo_elem_flag_set (bm, (ele)->oflags, oflag, val) #define BMO_elem_flag_toggle( bm, ele, oflag) _bmo_elem_flag_toggle (bm, (ele)->oflags, oflag) BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_enable( BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_disable( BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_set( BMesh *bm, BMFlagLayer *oflags, const short oflag, int val); BLI_INLINE void _bmo_elem_flag_toggle( BMesh *bm, BMFlagLayer *oflags, const short oflag); /* slot type arrays are terminated by the last member * having a slot type of 0 */ typedef enum eBMOpSlotType { /* BMO_OP_SLOT_SENTINEL = 0, */ BMO_OP_SLOT_BOOL = 1, BMO_OP_SLOT_INT = 2, BMO_OP_SLOT_FLT = 3, /* normally store pointers to object, scene, * _never_ store arrays corresponding to mesh elements with this */ BMO_OP_SLOT_PTR = 4, /* requres subtype BMO_OP_SLOT_SUBTYPE_PTR_xxx */ BMO_OP_SLOT_MAT = 5, BMO_OP_SLOT_VEC = 8, /* after BMO_OP_SLOT_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 */ BMO_OP_SLOT_ELEMENT_BUF = 9, /* list of verts/edges/faces */ BMO_OP_SLOT_MAPPING = 10 /* simple hash map, requres subtype BMO_OP_SLOT_SUBTYPE_MAP_xxx */ } eBMOpSlotType; #define BMO_OP_SLOT_TOTAL_TYPES 11 /* don't overlap values to avoid confusion */ typedef enum eBMOpSlotSubType_Elem { /* use as flags */ BMO_OP_SLOT_SUBTYPE_ELEM_VERT = BM_VERT, BMO_OP_SLOT_SUBTYPE_ELEM_EDGE = BM_EDGE, BMO_OP_SLOT_SUBTYPE_ELEM_FACE = BM_FACE, BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE = (BM_FACE << 1), } eBMOpSlotSubType_Elem; typedef enum eBMOpSlotSubType_Map { BMO_OP_SLOT_SUBTYPE_MAP_EMPTY = 64, /* use as a set(), unused value */ BMO_OP_SLOT_SUBTYPE_MAP_ELEM = 65, BMO_OP_SLOT_SUBTYPE_MAP_FLT = 66, BMO_OP_SLOT_SUBTYPE_MAP_INT = 67, BMO_OP_SLOT_SUBTYPE_MAP_BOOL = 68, BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL = 69, /* python can't convert these */ } eBMOpSlotSubType_Map; typedef enum eBMOpSlotSubType_Ptr { BMO_OP_SLOT_SUBTYPE_PTR_BMESH = 100, BMO_OP_SLOT_SUBTYPE_PTR_SCENE = 101, BMO_OP_SLOT_SUBTYPE_PTR_OBJECT = 102, BMO_OP_SLOT_SUBTYPE_PTR_MESH = 103, } eBMOpSlotSubType_Ptr; typedef union eBMOpSlotSubType_Union { eBMOpSlotSubType_Elem elem; eBMOpSlotSubType_Ptr ptr; eBMOpSlotSubType_Map map; } eBMOpSlotSubType_Union; /* please ignore all these structures, don't touch them in tool code, except * for when your defining an operator with BMOpDefine.*/ typedef struct BMOpSlot { const char *slot_name; /* pointer to BMOpDefine.slot_args */ eBMOpSlotType slot_type; eBMOpSlotSubType_Union slot_subtype; int len; // int flag; /* UNUSED */ // int index; /* index within slot array */ /* UNUSED */ union { int i; float f; void *p; float vec[3]; void **buf; GHash *ghash; } data; } BMOpSlot; /* mainly for use outside bmesh internal code */ #define BMO_SLOT_AS_BOOL(slot) ((slot)->data.i) #define BMO_SLOT_AS_INT(slot) ((slot)->data.i) #define BMO_SLOT_AS_FLOAT(slot) ((slot)->data.f) #define BMO_SLOT_AS_VECTOR(slot) ((slot)->data.vec) #define BMO_SLOT_AS_MATRIX(slot ) ((float (*)[4])((slot)->data.p)) #define BMO_SLOT_AS_BUFFER(slot ) ((slot)->data.buf) #define BMO_SLOT_AS_GHASH(slot ) ((slot)->data.ghash) #define BMO_ASSERT_SLOT_IN_OP(slot, op) \ BLI_assert(((slot >= (op)->slots_in) && (slot < &(op)->slots_in[BMO_OP_MAX_SLOTS])) || \ ((slot >= (op)->slots_out) && (slot < &(op)->slots_out[BMO_OP_MAX_SLOTS]))) /* way more than probably needed, compiler complains if limit hit */ #define BMO_OP_MAX_SLOTS 16 /* BMOpDefine->type_flag */ typedef enum { BMO_OPTYPE_FLAG_NOP = 0, BMO_OPTYPE_FLAG_UNTAN_MULTIRES = (1 << 0), /* switch from multires tangent space to absolute coordinates */ BMO_OPTYPE_FLAG_NORMALS_CALC = (1 << 1), BMO_OPTYPE_FLAG_SELECT_FLUSH = (1 << 2), BMO_OPTYPE_FLAG_SELECT_VALIDATE = (1 << 3), } BMOpTypeFlag; typedef struct BMOperator { struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]; struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]; void (*exec)(BMesh *bm, struct BMOperator *op); struct MemArena *arena; int type; BMOpTypeFlag type_flag; int flag; /* runtime options */ } BMOperator; enum { BMO_FLAG_RESPECT_HIDE = 1, }; #define BMO_FLAG_DEFAULTS BMO_FLAG_RESPECT_HIDE #define MAX_SLOTNAME 32 typedef struct BMOSlotType { char name[MAX_SLOTNAME]; eBMOpSlotType type; eBMOpSlotSubType_Union subtype; } BMOSlotType; typedef struct BMOpDefine { const char *opname; BMOSlotType slot_types_in[BMO_OP_MAX_SLOTS]; BMOSlotType slot_types_out[BMO_OP_MAX_SLOTS]; void (*exec)(BMesh *bm, BMOperator *op); BMOpTypeFlag type_flag; } BMOpDefine; /*------------- Operator API --------------*/ /* data types that use pointers (arrays, etc) should never * have it set directly. and never use BMO_slot_ptr_set to * pass in a list of edges or any arrays, really.*/ void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname); /* executes an operator, pushing and popping a new tool flag * layer as appropriate.*/ void BMO_op_exec(BMesh *bm, BMOperator *op); /* finishes an operator (though note the operator's tool flag is removed * after it finishes executing in BMO_op_exec).*/ void BMO_op_finish(BMesh *bm, BMOperator *op); /* count the number of elements with the specified flag enabled. * type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */ int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag); /* count the number of elements with the specified flag disabled. * type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */ int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag); /*---------formatted operator initialization/execution-----------*/ void BMO_push(BMesh *bm, BMOperator *op); void BMO_pop(BMesh *bm); /*executes an operator*/ bool BMO_op_callf(BMesh *bm, const int flag, 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/finish (BMO_op_exec and BMO_op_finish) yourself. */ bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, ...); /* va_list version, used to implement the above two functions, * plus EDBM_op_callf in editmesh_utils.c. */ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, va_list vlist); /* test whether a named slot exists */ bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier); /* get a pointer to a slot. this may be removed layer on from the public API. */ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier); /* copies the data of a slot from one operator to another. src and dst are the * source/destination slot codes, respectively. */ #define BMO_slot_copy(op_src, slots_src, slot_name_src, \ op_dst, slots_dst, slot_name_dst) \ _bmo_slot_copy((op_src)->slots_src, slot_name_src, \ (op_dst)->slots_dst, slot_name_dst, \ (op_dst)->arena) void _bmo_slot_copy( BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src, BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst, struct MemArena *arena_dst); /* del "context" slot values, used for operator too */ enum { DEL_VERTS = 1, DEL_EDGES, DEL_ONLYFACES, DEL_EDGESFACES, DEL_FACES, DEL_ONLYTAGGED }; typedef enum { BMO_SYMMETRIZE_NEGATIVE_X, BMO_SYMMETRIZE_NEGATIVE_Y, BMO_SYMMETRIZE_NEGATIVE_Z, BMO_SYMMETRIZE_POSITIVE_X, BMO_SYMMETRIZE_POSITIVE_Y, BMO_SYMMETRIZE_POSITIVE_Z, } BMO_SymmDirection; typedef enum { BMO_DELIM_NORMAL = 1 << 0, BMO_DELIM_MATERIAL = 1 << 1, BMO_DELIM_SEAM = 1 << 2, BMO_DELIM_SHARP = 1 << 3, BMO_DELIM_UV = 1 << 4, } BMO_Delimit; void BMO_op_flag_enable(BMesh *bm, BMOperator *op, const int op_flag); void BMO_op_flag_disable(BMesh *bm, BMOperator *op, const int op_flag); void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float f); float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i); int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i); bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len); /* 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_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, void *p); void *BMO_slot_ptr_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float vec[3]); void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3]); /* 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_MatXXX function you want. */ void BMO_slot_mat_set(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float *mat, int size); void BMO_slot_mat4_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_mat[4][4]); void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_mat[3][3]); void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag); void BMO_mesh_selected_remap( BMesh *bm, BMOpSlot *slot_vert_map, BMOpSlot *slot_edge_map, BMOpSlot *slot_face_map, const bool check_select); /* copies the values from another slot to the end of the output slot */ #define BMO_slot_buffer_append(op_src, slots_src, slot_name_src, \ op_dst, slots_dst, slot_name_dst) \ _bmo_slot_buffer_append((op_src)->slots_src, slot_name_src, \ (op_dst)->slots_dst, slot_name_dst, \ (op_dst)->arena) void _bmo_slot_buffer_append( BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst, BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src, struct MemArena *arena_dst); /* puts every element of type 'type' (which is a bitmask) with tool * flag 'flag', into a slot. */ void BMO_slot_buffer_from_enabled_flag( BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag); /* puts every element of type 'type' (which is a bitmask) without tool * flag 'flag', into a slot. */ void BMO_slot_buffer_from_disabled_flag( BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag); /* tool-flags all elements inside an element slot array with flag flag. */ void BMO_slot_buffer_flag_enable( BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag); /* clears tool-flag flag from all elements inside a slot array. */ void BMO_slot_buffer_flag_disable( BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag); /* tool-flags all elements inside an element slot array with flag flag. */ void BMO_slot_buffer_hflag_enable( BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag, const bool do_flush); /* clears tool-flag flag from all elements inside a slot array. */ void BMO_slot_buffer_hflag_disable( BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag, const bool do_flush); /* 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_ELEM_HIDDEN set).*/ void BMO_slot_buffer_from_enabled_hflag( BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag); /* puts every element of type 'type' (which is a bitmask) without * header flag 'flag', into a slot. note: ignores hidden elements * (e.g. elements with header flag BM_ELEM_HIDDEN set).*/ void BMO_slot_buffer_from_disabled_hflag( BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag); void BMO_slot_buffer_from_array(BMOperator *op, BMOpSlot *slot, BMHeader **ele_buffer, int ele_buffer_len); void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele); void *BMO_slot_buffer_get_single(BMOpSlot *slot); /* counts number of elements inside a slot array. */ int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); void BMO_slot_map_insert( BMOperator *op, BMOpSlot *slot, const void *element, const void *data); /* flags all elements in a mapping. note that the mapping must only have * bmesh elements in it.*/ void BMO_slot_map_to_flag( BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char hflag, const short oflag); void *BMO_slot_buffer_alloc( BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int len); void BMO_slot_buffer_from_all( BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype); /** * 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: * * \code{.c} * * BMOIter oiter; * BMFace *f; * * f = BMO_iter_new(&oiter, some_operator, "slot_name", BM_FACE); * for (; f; f = BMO_iter_step(&oiter)) { * /do something with the face * } * * another example, iterating over a mapping: * BMOIter oiter; * void *key; * void *val; * * key = BMO_iter_new(&oiter, bm, some_operator, "slot_name", 0); * for (; key; key = BMO_iter_step(&oiter)) { * val = BMO_iter_map_value(&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_iter_map_value(&oiter)); * //or something like that. * } * \endcode */ /* contents of this structure are private, * don't directly access. */ typedef struct BMOIter { BMOpSlot *slot; int cur; //for arrays GHashIterator giter; void **val; char restrictmask; /* bitwise '&' with BMHeader.htype */ } BMOIter; void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); void *BMO_iter_new( BMOIter *iter, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask); void *BMO_iter_step(BMOIter *iter); void **BMO_iter_map_value_p(BMOIter *iter); void *BMO_iter_map_value_ptr(BMOIter *iter); float BMO_iter_map_value_float(BMOIter *iter); int BMO_iter_map_value_int(BMOIter *iter); bool BMO_iter_map_value_bool(BMOIter *iter); #define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag) \ for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_new(iter, slot_args, slot_name, restrict_flag); \ ele; \ BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter)) #define BMO_ITER_INDEX(ele, iter, slot_args, slot_name, restrict_flag, i_) \ for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_new(iter, slot_args, slot_name, restrict_flag), i_ = 0; \ ele; \ BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter), i_++) extern const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES]; int BMO_opcode_from_opname(const char *opname); #ifdef __cplusplus } #endif #endif /* __BMESH_OPERATOR_API_H__ */