Cleanup: move public doc-strings into headers for 'bmesh'
Some minor improvements to doc-strings too. Ref T92709
This commit is contained in:
@@ -39,11 +39,6 @@
|
||||
|
||||
#define SELECT 1
|
||||
|
||||
/**
|
||||
* Fill in a vertex array from an edge array.
|
||||
*
|
||||
* \returns false if any verts aren't found.
|
||||
*/
|
||||
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
|
||||
{
|
||||
int i, i_prev = len - 1;
|
||||
@@ -57,11 +52,6 @@ bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in an edge array from a vertex array (connected polygon loop).
|
||||
*
|
||||
* \returns false if any edges aren't found.
|
||||
*/
|
||||
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
|
||||
{
|
||||
int i, i_prev = len - 1;
|
||||
@@ -75,10 +65,6 @@ bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in an edge array from a vertex array (connected polygon loop).
|
||||
* Creating edges as-needed.
|
||||
*/
|
||||
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
|
||||
{
|
||||
int i, i_prev = len - 1;
|
||||
@@ -93,20 +79,6 @@ void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr,
|
||||
static void bm_loop_attrs_copy(
|
||||
BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude);
|
||||
|
||||
/**
|
||||
* \brief Make Quad/Triangle
|
||||
*
|
||||
* Creates a new quad or triangle from a list of 3 or 4 vertices.
|
||||
* If \a no_double is true, then a check is done to see if a face
|
||||
* with these vertices already exists and returns it instead.
|
||||
*
|
||||
* If a pointer to an example face is provided, its custom data
|
||||
* and properties will be copied to the new face.
|
||||
*
|
||||
* \note The winding of the face is determined by the order
|
||||
* of the vertices in the vertex array.
|
||||
*/
|
||||
|
||||
BMFace *BM_face_create_quad_tri(BMesh *bm,
|
||||
BMVert *v1,
|
||||
BMVert *v2,
|
||||
@@ -119,16 +91,6 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
|
||||
return BM_face_create_verts(bm, vtar, v4 ? 4 : 3, f_example, create_flag, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief copies face loop data from shared adjacent faces.
|
||||
*
|
||||
* \param filter_fn: A function that filters the source loops before copying
|
||||
* (don't always want to copy all).
|
||||
*
|
||||
* \note when a matching edge is found, both loops of that edge are copied
|
||||
* this is done since the face may not be completely surrounded by faces,
|
||||
* this way: a quad with 2 connected quads on either side will still get all 4 loops updated
|
||||
*/
|
||||
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
|
||||
{
|
||||
BMLoop *l_first;
|
||||
@@ -260,20 +222,6 @@ error:
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Make NGon
|
||||
*
|
||||
* Makes an ngon from an unordered list of edges.
|
||||
* Verts \a v1 and \a v2 define the winding of the new face.
|
||||
*
|
||||
* \a edges are not required to be ordered, simply to form
|
||||
* a single closed loop as a whole.
|
||||
*
|
||||
* \note While this function will work fine when the edges
|
||||
* are already sorted, if the edges are always going to be sorted,
|
||||
* #BM_face_create should be considered over this function as it
|
||||
* avoids some unnecessary work.
|
||||
*/
|
||||
BMFace *BM_face_create_ngon(BMesh *bm,
|
||||
BMVert *v1,
|
||||
BMVert *v2,
|
||||
@@ -294,14 +242,6 @@ BMFace *BM_face_create_ngon(BMesh *bm,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ngon from an array of sorted verts
|
||||
*
|
||||
* Special features this has over other functions.
|
||||
* - Optionally calculate winding based on surrounding edges.
|
||||
* - Optionally create edges between vertices.
|
||||
* - Uses verts so no need to find edges (handy when you only have verts)
|
||||
*/
|
||||
BMFace *BM_face_create_ngon_verts(BMesh *bm,
|
||||
BMVert **vert_arr,
|
||||
const int len,
|
||||
@@ -367,22 +307,6 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm,
|
||||
bm, v_winding[winding[0]], v_winding[winding[1]], edge_arr, len, f_example, create_flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an NGon from an un-ordered set of verts
|
||||
*
|
||||
* assumes...
|
||||
* - that verts are only once in the list.
|
||||
* - that the verts have roughly planer bounds
|
||||
* - that the verts are roughly circular
|
||||
* there can be concave areas but overlapping folds from the center point will fail.
|
||||
*
|
||||
* a brief explanation of the method used
|
||||
* - find the center point
|
||||
* - find the normal of the vcloud
|
||||
* - order the verts around the face based on their angle to the normal vector at the center point.
|
||||
*
|
||||
* \note Since this is a vcloud there is no direction.
|
||||
*/
|
||||
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
|
||||
{
|
||||
struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
|
||||
@@ -470,10 +394,6 @@ static void bm_face_attrs_copy(
|
||||
/* BMESH_TODO: Special handling for hide flags? */
|
||||
/* BMESH_TODO: swap src/dst args, everywhere else in bmesh does other way round */
|
||||
|
||||
/**
|
||||
* Copies attributes, e.g. customdata, header flags, etc, from one element
|
||||
* to another of the same type.
|
||||
*/
|
||||
void BM_elem_attrs_copy_ex(BMesh *bm_src,
|
||||
BMesh *bm_dst,
|
||||
const void *ele_src_v,
|
||||
@@ -626,15 +546,6 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem
|
||||
CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to #BM_mesh_copy_init_customdata but copies all layers ignoring
|
||||
* flags like #CD_FLAG_NOCOPY.
|
||||
*
|
||||
* \param bm_dst: BMesh whose custom-data layers will be added.
|
||||
* \param bm_src: BMesh whose custom-data layers will be copied.
|
||||
* \param htype: Specifies which custom-data layers will be initiated.
|
||||
* \param allocsize: Initialize the memory-pool before use (may be an estimate).
|
||||
*/
|
||||
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
|
||||
BMesh *bm_src,
|
||||
const char htype,
|
||||
@@ -786,7 +697,6 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
|
||||
return bm_new;
|
||||
}
|
||||
|
||||
/* ME -> BM */
|
||||
char BM_vert_flag_from_mflag(const char mflag)
|
||||
{
|
||||
return (((mflag & SELECT) ? BM_ELEM_SELECT : 0) | ((mflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0));
|
||||
@@ -804,7 +714,6 @@ char BM_face_flag_from_mflag(const char mflag)
|
||||
((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0) | ((mflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0));
|
||||
}
|
||||
|
||||
/* BM -> ME */
|
||||
char BM_vert_flag_to_mflag(BMVert *v)
|
||||
{
|
||||
const char hflag = v->head.hflag;
|
||||
|
||||
@@ -25,14 +25,57 @@
|
||||
struct BMAllocTemplate;
|
||||
struct Mesh;
|
||||
|
||||
/**
|
||||
* Fill in a vertex array from an edge array.
|
||||
*
|
||||
* \returns false if any verts aren't found.
|
||||
*/
|
||||
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len);
|
||||
|
||||
/**
|
||||
* Fill in an edge array from a vertex array (connected polygon loop).
|
||||
*
|
||||
* \returns false if any edges aren't found.
|
||||
*/
|
||||
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len);
|
||||
/**
|
||||
* Fill in an edge array from a vertex array (connected polygon loop).
|
||||
* Creating edges as-needed.
|
||||
*/
|
||||
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len);
|
||||
|
||||
/* sort before creation */
|
||||
/**
|
||||
* Makes an NGon from an un-ordered set of verts.
|
||||
*
|
||||
* Assumes:
|
||||
* - that verts are only once in the list.
|
||||
* - that the verts have roughly planer bounds
|
||||
* - that the verts are roughly circular
|
||||
*
|
||||
* There can be concave areas but overlapping folds from the center point will fail.
|
||||
*
|
||||
* A brief explanation of the method used
|
||||
* - find the center point
|
||||
* - find the normal of the vertex-cloud
|
||||
* - order the verts around the face based on their angle to the normal vector at the center point.
|
||||
*
|
||||
* \note Since this is a vertex-cloud there is no direction.
|
||||
*/
|
||||
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len);
|
||||
|
||||
/**
|
||||
* \brief Make Quad/Triangle
|
||||
*
|
||||
* Creates a new quad or triangle from a list of 3 or 4 vertices.
|
||||
* If \a no_double is true, then a check is done to see if a face
|
||||
* with these vertices already exists and returns it instead.
|
||||
*
|
||||
* If a pointer to an example face is provided, its custom data
|
||||
* and properties will be copied to the new face.
|
||||
*
|
||||
* \note The winding of the face is determined by the order
|
||||
* of the vertices in the vertex array.
|
||||
*/
|
||||
BMFace *BM_face_create_quad_tri(BMesh *bm,
|
||||
BMVert *v1,
|
||||
BMVert *v2,
|
||||
@@ -41,8 +84,32 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
|
||||
const BMFace *f_example,
|
||||
const eBMCreateFlag create_flag);
|
||||
|
||||
/**
|
||||
* \brief copies face loop data from shared adjacent faces.
|
||||
*
|
||||
* \param filter_fn: A function that filters the source loops before copying
|
||||
* (don't always want to copy all).
|
||||
*
|
||||
* \note when a matching edge is found, both loops of that edge are copied
|
||||
* this is done since the face may not be completely surrounded by faces,
|
||||
* this way: a quad with 2 connected quads on either side will still get all 4 loops updated
|
||||
*/
|
||||
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data);
|
||||
|
||||
/**
|
||||
* \brief Make NGon
|
||||
*
|
||||
* Makes an ngon from an unordered list of edges.
|
||||
* Verts \a v1 and \a v2 define the winding of the new face.
|
||||
*
|
||||
* \a edges are not required to be ordered, simply to form
|
||||
* a single closed loop as a whole.
|
||||
*
|
||||
* \note While this function will work fine when the edges
|
||||
* are already sorted, if the edges are always going to be sorted,
|
||||
* #BM_face_create should be considered over this function as it
|
||||
* avoids some unnecessary work.
|
||||
*/
|
||||
BMFace *BM_face_create_ngon(BMesh *bm,
|
||||
BMVert *v1,
|
||||
BMVert *v2,
|
||||
@@ -50,6 +117,14 @@ BMFace *BM_face_create_ngon(BMesh *bm,
|
||||
const int len,
|
||||
const BMFace *f_example,
|
||||
const eBMCreateFlag create_flag);
|
||||
/**
|
||||
* Create an ngon from an array of sorted verts
|
||||
*
|
||||
* Special features this has over other functions.
|
||||
* - Optionally calculate winding based on surrounding edges.
|
||||
* - Optionally create edges between vertices.
|
||||
* - Uses verts so no need to find edges (handy when you only have verts)
|
||||
*/
|
||||
BMFace *BM_face_create_ngon_verts(BMesh *bm,
|
||||
BMVert **vert_arr,
|
||||
const int len,
|
||||
@@ -58,6 +133,10 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm,
|
||||
const bool calc_winding,
|
||||
const bool create_edges);
|
||||
|
||||
/**
|
||||
* Copies attributes, e.g. customdata, header flags, etc, from one element
|
||||
* to another of the same type.
|
||||
*/
|
||||
void BM_elem_attrs_copy_ex(BMesh *bm_src,
|
||||
BMesh *bm_dst,
|
||||
const void *ele_src_v,
|
||||
@@ -73,6 +152,15 @@ void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,
|
||||
void BM_mesh_copy_init_customdata(BMesh *bm_dst,
|
||||
BMesh *bm_src,
|
||||
const struct BMAllocTemplate *allocsize);
|
||||
/**
|
||||
* Similar to #BM_mesh_copy_init_customdata but copies all layers ignoring
|
||||
* flags like #CD_FLAG_NOCOPY.
|
||||
*
|
||||
* \param bm_dst: BMesh whose custom-data layers will be added.
|
||||
* \param bm_src: BMesh whose custom-data layers will be copied.
|
||||
* \param htype: Specifies which custom-data layers will be initiated.
|
||||
* \param allocsize: Initialize the memory-pool before use (may be an estimate).
|
||||
*/
|
||||
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
|
||||
BMesh *bm_src,
|
||||
const char htype,
|
||||
@@ -81,7 +169,9 @@ BMesh *BM_mesh_copy(BMesh *bm_old);
|
||||
|
||||
char BM_face_flag_from_mflag(const char mflag);
|
||||
char BM_edge_flag_from_mflag(const short mflag);
|
||||
/* ME -> BM */
|
||||
char BM_vert_flag_from_mflag(const char mflag);
|
||||
char BM_face_flag_to_mflag(BMFace *f);
|
||||
short BM_edge_flag_to_mflag(BMEdge *e);
|
||||
/* BM -> ME */
|
||||
char BM_vert_flag_to_mflag(BMVert *v);
|
||||
|
||||
@@ -52,9 +52,6 @@
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Main function for creating a new vertex.
|
||||
*/
|
||||
BMVert *BM_vert_create(BMesh *bm,
|
||||
const float co[3],
|
||||
const BMVert *v_example,
|
||||
@@ -137,13 +134,6 @@ BMVert *BM_vert_create(BMesh *bm,
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Main function for creating a new edge.
|
||||
*
|
||||
* \note Duplicate edges are supported by the API however users should _never_ see them.
|
||||
* so unless you need a unique edge or know the edge won't exist,
|
||||
* you should call with \a no_double = true.
|
||||
*/
|
||||
BMEdge *BM_edge_create(
|
||||
BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
|
||||
{
|
||||
@@ -416,15 +406,6 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main face creation function
|
||||
*
|
||||
* \param bm: The mesh
|
||||
* \param verts: A sorted array of verts size of len
|
||||
* \param edges: A sorted array of edges size of len
|
||||
* \param len: Length of the face
|
||||
* \param create_flag: Options for creating the face
|
||||
*/
|
||||
BMFace *BM_face_create(BMesh *bm,
|
||||
BMVert **verts,
|
||||
BMEdge **edges,
|
||||
@@ -494,9 +475,6 @@ BMFace *BM_face_create(BMesh *bm,
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for #BM_face_create when you don't have an edge array
|
||||
*/
|
||||
BMFace *BM_face_create_verts(BMesh *bm,
|
||||
BMVert **vert_arr,
|
||||
const int len,
|
||||
@@ -520,12 +498,6 @@ BMFace *BM_face_create_verts(BMesh *bm,
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/**
|
||||
* Check the element is valid.
|
||||
*
|
||||
* BMESH_TODO, when this raises an error the output is incredibly confusing.
|
||||
* need to have some nice way to print/debug what the heck's going on.
|
||||
*/
|
||||
int bmesh_elem_check(void *element, const char htype)
|
||||
{
|
||||
BMHeader *head = element;
|
||||
@@ -833,10 +805,6 @@ static void bm_kill_only_loop(BMesh *bm, BMLoop *l)
|
||||
BLI_mempool_free(bm->lpool, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* kills all edges associated with \a f, along with any other faces containing
|
||||
* those edges
|
||||
*/
|
||||
void BM_face_edges_kill(BMesh *bm, BMFace *f)
|
||||
{
|
||||
BMEdge **edges = BLI_array_alloca(edges, f->len);
|
||||
@@ -854,10 +822,6 @@ void BM_face_edges_kill(BMesh *bm, BMFace *f)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kills all verts associated with \a f, along with any other faces containing
|
||||
* those vertices
|
||||
*/
|
||||
void BM_face_verts_kill(BMesh *bm, BMFace *f)
|
||||
{
|
||||
BMVert **verts = BLI_array_alloca(verts, f->len);
|
||||
@@ -875,9 +839,6 @@ void BM_face_verts_kill(BMesh *bm, BMFace *f)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kills \a f and its loops.
|
||||
*/
|
||||
void BM_face_kill(BMesh *bm, BMFace *f)
|
||||
{
|
||||
#ifdef USE_BMESH_HOLES
|
||||
@@ -922,10 +883,6 @@ void BM_face_kill(BMesh *bm, BMFace *f)
|
||||
bm_kill_only_face(bm, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #BM_face_kill which removes edges and verts
|
||||
* which have no remaining connected geometry.
|
||||
*/
|
||||
void BM_face_kill_loose(BMesh *bm, BMFace *f)
|
||||
{
|
||||
#ifdef USE_BMESH_HOLES
|
||||
@@ -981,9 +938,6 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f)
|
||||
bm_kill_only_face(bm, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* kills \a e and all faces that use it.
|
||||
*/
|
||||
void BM_edge_kill(BMesh *bm, BMEdge *e)
|
||||
{
|
||||
while (e->l) {
|
||||
@@ -996,9 +950,6 @@ void BM_edge_kill(BMesh *bm, BMEdge *e)
|
||||
bm_kill_only_edge(bm, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* kills \a v and all edges that use it.
|
||||
*/
|
||||
void BM_vert_kill(BMesh *bm, BMVert *v)
|
||||
{
|
||||
while (v->e) {
|
||||
@@ -1025,15 +976,6 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Loop Reverse
|
||||
*
|
||||
* Changes the winding order of a face from CW to CCW or vice versa.
|
||||
*
|
||||
* \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
|
||||
* \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
|
||||
* (use when flipping normals, disable when mirroring, eg: symmetrize).
|
||||
*/
|
||||
void bmesh_kernel_loop_reverse(BMesh *bm,
|
||||
BMFace *f,
|
||||
const int cd_loop_mdisp_offset,
|
||||
@@ -1192,20 +1134,6 @@ static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
|
||||
|
||||
/* Mid-level Topology Manipulation Functions */
|
||||
|
||||
/**
|
||||
* \brief Join Connected Faces
|
||||
*
|
||||
* Joins a collected group of faces into one. Only restriction on
|
||||
* the input data is that the faces must be connected to each other.
|
||||
*
|
||||
* \return The newly created combine BMFace.
|
||||
*
|
||||
* \note If a pair of faces share multiple edges,
|
||||
* the pair of faces will be joined at every edge.
|
||||
*
|
||||
* \note this is a generic, flexible join faces function,
|
||||
* almost everything uses this, including #BM_faces_join_pair
|
||||
*/
|
||||
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
|
||||
{
|
||||
BMFace *f, *f_new;
|
||||
@@ -1422,44 +1350,6 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *f_example)
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Split Face Make Edge (SFME)
|
||||
*
|
||||
* \warning this is a low level function, most likely you want to use #BM_face_split()
|
||||
*
|
||||
* Takes as input two vertices in a single face.
|
||||
* An edge is created which divides the original face into two distinct regions.
|
||||
* One of the regions is assigned to the original face and it is closed off.
|
||||
* The second region has a new face assigned to it.
|
||||
*
|
||||
* \par Examples:
|
||||
* <pre>
|
||||
* Before: After:
|
||||
* +--------+ +--------+
|
||||
* | | | |
|
||||
* | | | f1 |
|
||||
* v1 f1 v2 v1======v2
|
||||
* | | | f2 |
|
||||
* | | | |
|
||||
* +--------+ +--------+
|
||||
* </pre>
|
||||
*
|
||||
* \note the input vertices can be part of the same edge. This will
|
||||
* result in a two edged face. This is desirable for advanced construction
|
||||
* tools and particularly essential for edge bevel. Because of this it is
|
||||
* up to the caller to decide what to do with the extra edge.
|
||||
*
|
||||
* \note If \a holes is NULL, then both faces will lose
|
||||
* all holes from the original face. Also, you cannot split between
|
||||
* a hole vert and a boundary vert; that case is handled by higher-
|
||||
* level wrapping functions (when holes are fully implemented, anyway).
|
||||
*
|
||||
* \note that holes represents which holes goes to the new face, and of
|
||||
* course this requires removing them from the existing face first, since
|
||||
* you cannot have linked list links inside multiple lists.
|
||||
*
|
||||
* \return A BMFace pointer
|
||||
*/
|
||||
BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMLoop *l_v1,
|
||||
@@ -1599,24 +1489,6 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
|
||||
return f2;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Split Edge Make Vert (SEMV)
|
||||
*
|
||||
* Takes \a e edge and splits it into two, creating a new vert.
|
||||
* \a tv should be one end of \a e : the newly created edge
|
||||
* will be attached to that end and is returned in \a r_e.
|
||||
*
|
||||
* \par Examples:
|
||||
*
|
||||
* <pre>
|
||||
* E
|
||||
* Before: OV-------------TV
|
||||
* E RE
|
||||
* After: OV------NV-----TV
|
||||
* </pre>
|
||||
*
|
||||
* \return The newly created BMVert pointer.
|
||||
*/
|
||||
BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
|
||||
{
|
||||
BMLoop *l_next;
|
||||
@@ -1770,36 +1642,6 @@ BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEd
|
||||
return v_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Join Edge Kill Vert (JEKV)
|
||||
*
|
||||
* Takes an edge \a e_kill and pointer to one of its vertices \a v_kill
|
||||
* and collapses the edge on that vertex.
|
||||
*
|
||||
* \par Examples:
|
||||
*
|
||||
* <pre>
|
||||
* Before: e_old e_kill
|
||||
* +-------+-------+
|
||||
* | | |
|
||||
* v_old v_kill v_target
|
||||
*
|
||||
* After: e_old
|
||||
* +---------------+
|
||||
* | |
|
||||
* v_old v_target
|
||||
* </pre>
|
||||
*
|
||||
* \par Restrictions:
|
||||
* KV is a vertex that must have a valance of exactly two. Furthermore
|
||||
* both edges in KV's disk cycle (OE and KE) must be unique (no double edges).
|
||||
*
|
||||
* \return The resulting edge, NULL for failure.
|
||||
*
|
||||
* \note This euler has the possibility of creating
|
||||
* faces with just 2 edges. It is up to the caller to decide what to do with
|
||||
* these faces.
|
||||
*/
|
||||
BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
|
||||
BMEdge *e_kill,
|
||||
BMVert *v_kill,
|
||||
@@ -1967,24 +1809,6 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Join Vert Kill Edge (JVKE)
|
||||
*
|
||||
* Collapse an edge, merging surrounding data.
|
||||
*
|
||||
* Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert
|
||||
* which only handle 2 valence verts,
|
||||
* this can handle any number of connected edges/faces.
|
||||
*
|
||||
* <pre>
|
||||
* Before: -> After:
|
||||
* +-+-+-+ +-+-+-+
|
||||
* | | | | | \ / |
|
||||
* +-+-+-+ +--+--+
|
||||
* | | | | | / \ |
|
||||
* +-+-+-+ +-+-+-+
|
||||
* </pre>
|
||||
*/
|
||||
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
|
||||
BMEdge *e_kill,
|
||||
BMVert *v_kill,
|
||||
@@ -2068,37 +1892,6 @@ BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
|
||||
return v_target;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Join Face Kill Edge (JFKE)
|
||||
*
|
||||
* Takes two faces joined by a single 2-manifold edge and fuses them together.
|
||||
* The edge shared by the faces must not be connected to any other edges which have
|
||||
* Both faces in its radial cycle
|
||||
*
|
||||
* \par Examples:
|
||||
* <pre>
|
||||
* A B
|
||||
* +--------+ +--------+
|
||||
* | | | |
|
||||
* | f1 | | f1 |
|
||||
* v1========v2 = Ok! v1==V2==v3 == Wrong!
|
||||
* | f2 | | f2 |
|
||||
* | | | |
|
||||
* +--------+ +--------+
|
||||
* </pre>
|
||||
*
|
||||
* In the example A, faces \a f1 and \a f2 are joined by a single edge,
|
||||
* and the euler can safely be used.
|
||||
* In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
|
||||
* The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
|
||||
* before attempting to fuse \a f1 and \a f2.
|
||||
*
|
||||
* \note The order of arguments decides whether or not certain per-face attributes are present
|
||||
* in the resultant face. For instance vertex winding, material index, smooth flags,
|
||||
* etc are inherited from \a f1, not \a f2.
|
||||
*
|
||||
* \return A BMFace pointer
|
||||
*/
|
||||
BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
|
||||
{
|
||||
BMLoop *l_iter, *l_f1 = NULL, *l_f2 = NULL;
|
||||
@@ -2221,11 +2014,6 @@ BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEd
|
||||
return f1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if splicing vertices would create any double edges.
|
||||
*
|
||||
* \note assume caller will handle case where verts share an edge.
|
||||
*/
|
||||
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
|
||||
{
|
||||
bool is_double = false;
|
||||
@@ -2269,18 +2057,6 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
|
||||
return is_double;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Splice Vert
|
||||
*
|
||||
* Merges two verts into one
|
||||
* (\a v_src into \a v_dst, removing \a v_src).
|
||||
*
|
||||
* \return Success
|
||||
*
|
||||
* \warning This doesn't work for collapsing edges,
|
||||
* where \a v and \a vtarget are connected by an edge
|
||||
* (assert checks for this case).
|
||||
*/
|
||||
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
|
||||
{
|
||||
BMEdge *e;
|
||||
@@ -2317,17 +2093,6 @@ BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
|
||||
return (e->l && e->l->radial_next != e->l);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Separate Vert
|
||||
*
|
||||
* Separates all disjoint fans that meet at a vertex, making a unique
|
||||
* vertex for each region. returns an array of all resulting vertices.
|
||||
*
|
||||
* \note this is a low level function, bm_edge_separate needs to run on edges first
|
||||
* or, the faces sharing verts must not be sharing edges for them to split at least.
|
||||
*
|
||||
* \return Success
|
||||
*/
|
||||
void bmesh_kernel_vert_separate(
|
||||
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
|
||||
{
|
||||
@@ -2480,9 +2245,6 @@ static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separ
|
||||
} while ((edges_separate = edges_separate->next));
|
||||
}
|
||||
|
||||
/**
|
||||
* High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
|
||||
*/
|
||||
void BM_vert_separate(BMesh *bm,
|
||||
BMVert *v,
|
||||
BMEdge **e_in,
|
||||
@@ -2516,9 +2278,6 @@ void BM_vert_separate(BMesh *bm,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #BM_vert_separate which takes a flag.
|
||||
*/
|
||||
void BM_vert_separate_hflag(BMesh *bm,
|
||||
BMVert *v,
|
||||
const char hflag,
|
||||
@@ -2584,16 +2343,6 @@ void BM_vert_separate_tested_edges(BMesh *UNUSED(bm),
|
||||
|
||||
/** \} */
|
||||
|
||||
/**
|
||||
* \brief Splice Edge
|
||||
*
|
||||
* Splice two unique edges which share the same two vertices into one edge.
|
||||
* (\a e_src into \a e_dst, removing e_src).
|
||||
*
|
||||
* \return Success
|
||||
*
|
||||
* \note Edges must already have the same vertices.
|
||||
*/
|
||||
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
|
||||
{
|
||||
BMLoop *l;
|
||||
@@ -2627,17 +2376,6 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Separate Edge
|
||||
*
|
||||
* Separates a single edge into two edge: the original edge and
|
||||
* a new edge that has only \a l_sep in its radial.
|
||||
*
|
||||
* \return Success
|
||||
*
|
||||
* \note Does nothing if \a l_sep is already the only loop in the
|
||||
* edge radial.
|
||||
*/
|
||||
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
|
||||
{
|
||||
BMEdge *e_new;
|
||||
@@ -2673,15 +2411,6 @@ void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool
|
||||
BM_CHECK_ELEMENT(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Un-glue Region Make Vert (URMV)
|
||||
*
|
||||
* Disconnects a face from its vertex fan at loop \a l_sep
|
||||
*
|
||||
* \return The newly created BMVert
|
||||
*
|
||||
* \note Will be a no-op and return original vertex if only two edges at that vertex.
|
||||
*/
|
||||
BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
|
||||
{
|
||||
BMVert *v_new = NULL;
|
||||
@@ -2744,13 +2473,6 @@ BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
|
||||
return v_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
|
||||
* The loops must all share the same vertex, can be in any order
|
||||
* and are all moved to use a single new vertex - which is returned.
|
||||
*
|
||||
* This function handles the details of finding fans boundaries.
|
||||
*/
|
||||
BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len)
|
||||
{
|
||||
BMVert *v_sep = larr[0]->v;
|
||||
@@ -2931,10 +2653,6 @@ static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_
|
||||
} while ((l_iter = l_iter->radial_next) != l_first);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function assumes l_sep is a part of a larger fan which has already been
|
||||
* isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
|
||||
*/
|
||||
BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
|
||||
{
|
||||
BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP);
|
||||
@@ -2944,11 +2662,6 @@ BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l
|
||||
return v_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid calling this where possible,
|
||||
* low level function so both face pointers remain intact but point to swapped data.
|
||||
* \note must be from the same bmesh.
|
||||
*/
|
||||
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b)
|
||||
{
|
||||
BMLoop *l_iter, *l_first;
|
||||
|
||||
@@ -25,26 +25,50 @@ BMFace *BM_face_copy(
|
||||
|
||||
typedef enum eBMCreateFlag {
|
||||
BM_CREATE_NOP = 0,
|
||||
/* faces and edges only */
|
||||
/** Faces and edges only. */
|
||||
BM_CREATE_NO_DOUBLE = (1 << 1),
|
||||
/* Skip CustomData - for all element types data,
|
||||
* use if we immediately write customdata into the element so this skips copying from 'example'
|
||||
* args or setting defaults, speeds up conversion when data is converted all at once. */
|
||||
/**
|
||||
* Skip custom-data - for all element types data,
|
||||
* use if we immediately write custom-data into the element so this skips copying from 'example'
|
||||
* arguments or setting defaults, speeds up conversion when data is converted all at once.
|
||||
*/
|
||||
BM_CREATE_SKIP_CD = (1 << 2),
|
||||
} eBMCreateFlag;
|
||||
|
||||
/**
|
||||
* \brief Main function for creating a new vertex.
|
||||
*/
|
||||
BMVert *BM_vert_create(BMesh *bm,
|
||||
const float co[3],
|
||||
const BMVert *v_example,
|
||||
const eBMCreateFlag create_flag);
|
||||
/**
|
||||
* \brief Main function for creating a new edge.
|
||||
*
|
||||
* \note Duplicate edges are supported by the API however users should _never_ see them.
|
||||
* so unless you need a unique edge or know the edge won't exist,
|
||||
* you should call with \a no_double = true.
|
||||
*/
|
||||
BMEdge *BM_edge_create(
|
||||
BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag);
|
||||
/**
|
||||
* Main face creation function
|
||||
*
|
||||
* \param bm: The mesh
|
||||
* \param verts: A sorted array of verts size of len
|
||||
* \param edges: A sorted array of edges size of len
|
||||
* \param len: Length of the face
|
||||
* \param create_flag: Options for creating the face
|
||||
*/
|
||||
BMFace *BM_face_create(BMesh *bm,
|
||||
BMVert **verts,
|
||||
BMEdge **edges,
|
||||
const int len,
|
||||
const BMFace *f_example,
|
||||
const eBMCreateFlag create_flag);
|
||||
/**
|
||||
* Wrapper for #BM_face_create when you don't have an edge array
|
||||
*/
|
||||
BMFace *BM_face_create_verts(BMesh *bm,
|
||||
BMVert **vert_arr,
|
||||
const int len,
|
||||
@@ -52,27 +76,105 @@ BMFace *BM_face_create_verts(BMesh *bm,
|
||||
const eBMCreateFlag create_flag,
|
||||
const bool create_edges);
|
||||
|
||||
/**
|
||||
* Kills all edges associated with \a f, along with any other faces containing those edges.
|
||||
*/
|
||||
void BM_face_edges_kill(BMesh *bm, BMFace *f);
|
||||
/**
|
||||
* kills all verts associated with \a f, along with any other faces containing
|
||||
* those vertices
|
||||
*/
|
||||
void BM_face_verts_kill(BMesh *bm, BMFace *f);
|
||||
|
||||
/**
|
||||
* A version of #BM_face_kill which removes edges and verts
|
||||
* which have no remaining connected geometry.
|
||||
*/
|
||||
void BM_face_kill_loose(BMesh *bm, BMFace *f);
|
||||
|
||||
/**
|
||||
* Kills \a f and its loops.
|
||||
*/
|
||||
void BM_face_kill(BMesh *bm, BMFace *f);
|
||||
/**
|
||||
* Kills \a e and all faces that use it.
|
||||
*/
|
||||
void BM_edge_kill(BMesh *bm, BMEdge *e);
|
||||
/**
|
||||
* Kills \a v and all edges that use it.
|
||||
*/
|
||||
void BM_vert_kill(BMesh *bm, BMVert *v);
|
||||
|
||||
/**
|
||||
* \brief Splice Edge
|
||||
*
|
||||
* Splice two unique edges which share the same two vertices into one edge.
|
||||
* (\a e_src into \a e_dst, removing e_src).
|
||||
*
|
||||
* \return Success
|
||||
*
|
||||
* \note Edges must already have the same vertices.
|
||||
*/
|
||||
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src);
|
||||
/**
|
||||
* \brief Splice Vert
|
||||
*
|
||||
* Merges two verts into one
|
||||
* (\a v_src into \a v_dst, removing \a v_src).
|
||||
*
|
||||
* \return Success
|
||||
*
|
||||
* \warning This doesn't work for collapsing edges,
|
||||
* where \a v and \a vtarget are connected by an edge
|
||||
* (assert checks for this case).
|
||||
*/
|
||||
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src);
|
||||
/**
|
||||
* Check if splicing vertices would create any double edges.
|
||||
*
|
||||
* \note assume caller will handle case where verts share an edge.
|
||||
*/
|
||||
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b);
|
||||
|
||||
/**
|
||||
* \brief Loop Reverse
|
||||
*
|
||||
* Changes the winding order of a face from CW to CCW or vice versa.
|
||||
*
|
||||
* \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
|
||||
* \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
|
||||
* (use when flipping normals, disable when mirroring, eg: symmetrize).
|
||||
*/
|
||||
void bmesh_kernel_loop_reverse(BMesh *bm,
|
||||
BMFace *f,
|
||||
const int cd_loop_mdisp_offset,
|
||||
const bool use_loop_mdisp_flip);
|
||||
|
||||
/**
|
||||
* Avoid calling this where possible,
|
||||
* low level function so both face pointers remain intact but point to swapped data.
|
||||
* \note must be from the same bmesh.
|
||||
*/
|
||||
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
|
||||
|
||||
/**
|
||||
* \brief Join Connected Faces
|
||||
*
|
||||
* Joins a collected group of faces into one. Only restriction on
|
||||
* the input data is that the faces must be connected to each other.
|
||||
*
|
||||
* \return The newly created combine BMFace.
|
||||
*
|
||||
* \note If a pair of faces share multiple edges,
|
||||
* the pair of faces will be joined at every edge.
|
||||
*
|
||||
* \note this is a generic, flexible join faces function,
|
||||
* almost everything uses this, including #BM_faces_join_pair
|
||||
*/
|
||||
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
|
||||
/**
|
||||
* High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
|
||||
*/
|
||||
void BM_vert_separate(BMesh *bm,
|
||||
BMVert *v,
|
||||
BMEdge **e_in,
|
||||
@@ -80,6 +182,9 @@ void BM_vert_separate(BMesh *bm,
|
||||
const bool copy_select,
|
||||
BMVert ***r_vout,
|
||||
int *r_vout_len);
|
||||
/**
|
||||
* A version of #BM_vert_separate which takes a flag.
|
||||
*/
|
||||
void BM_vert_separate_hflag(BMesh *bm,
|
||||
BMVert *v,
|
||||
const char hflag,
|
||||
@@ -94,10 +199,70 @@ void BM_vert_separate_tested_edges(
|
||||
*
|
||||
* Names are on the verbose side but these are only for low-level access.
|
||||
*/
|
||||
/**
|
||||
* \brief Separate Vert
|
||||
*
|
||||
* Separates all disjoint fans that meet at a vertex, making a unique
|
||||
* vertex for each region. returns an array of all resulting vertices.
|
||||
*
|
||||
* \note this is a low level function, bm_edge_separate needs to run on edges first
|
||||
* or, the faces sharing verts must not be sharing edges for them to split at least.
|
||||
*
|
||||
* \return Success
|
||||
*/
|
||||
void bmesh_kernel_vert_separate(
|
||||
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select);
|
||||
/**
|
||||
* \brief Separate Edge
|
||||
*
|
||||
* Separates a single edge into two edge: the original edge and
|
||||
* a new edge that has only \a l_sep in its radial.
|
||||
*
|
||||
* \return Success
|
||||
*
|
||||
* \note Does nothing if \a l_sep is already the only loop in the
|
||||
* edge radial.
|
||||
*/
|
||||
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select);
|
||||
|
||||
/**
|
||||
* \brief Split Face Make Edge (SFME)
|
||||
*
|
||||
* \warning this is a low level function, most likely you want to use #BM_face_split()
|
||||
*
|
||||
* Takes as input two vertices in a single face.
|
||||
* An edge is created which divides the original face into two distinct regions.
|
||||
* One of the regions is assigned to the original face and it is closed off.
|
||||
* The second region has a new face assigned to it.
|
||||
*
|
||||
* \par Examples:
|
||||
* <pre>
|
||||
* Before: After:
|
||||
* +--------+ +--------+
|
||||
* | | | |
|
||||
* | | | f1 |
|
||||
* v1 f1 v2 v1======v2
|
||||
* | | | f2 |
|
||||
* | | | |
|
||||
* +--------+ +--------+
|
||||
* </pre>
|
||||
*
|
||||
* \note the input vertices can be part of the same edge. This will
|
||||
* result in a two edged face. This is desirable for advanced construction
|
||||
* tools and particularly essential for edge bevel. Because of this it is
|
||||
* up to the caller to decide what to do with the extra edge.
|
||||
*
|
||||
* \note If \a holes is NULL, then both faces will lose
|
||||
* all holes from the original face. Also, you cannot split between
|
||||
* a hole vert and a boundary vert; that case is handled by higher-
|
||||
* level wrapping functions (when holes are fully implemented, anyway).
|
||||
*
|
||||
* \note that holes represents which holes goes to the new face, and of
|
||||
* course this requires removing them from the existing face first, since
|
||||
* you cannot have linked list links inside multiple lists.
|
||||
*
|
||||
* \return A BMFace pointer
|
||||
*/
|
||||
BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMLoop *l_v1,
|
||||
@@ -109,7 +274,55 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
|
||||
BMEdge *example,
|
||||
const bool no_double);
|
||||
|
||||
/**
|
||||
* \brief Split Edge Make Vert (SEMV)
|
||||
*
|
||||
* Takes \a e edge and splits it into two, creating a new vert.
|
||||
* \a tv should be one end of \a e : the newly created edge
|
||||
* will be attached to that end and is returned in \a r_e.
|
||||
*
|
||||
* \par Examples:
|
||||
*
|
||||
* <pre>
|
||||
* E
|
||||
* Before: OV-------------TV
|
||||
* E RE
|
||||
* After: OV------NV-----TV
|
||||
* </pre>
|
||||
*
|
||||
* \return The newly created BMVert pointer.
|
||||
*/
|
||||
BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
|
||||
/**
|
||||
* \brief Join Edge Kill Vert (JEKV)
|
||||
*
|
||||
* Takes an edge \a e_kill and pointer to one of its vertices \a v_kill
|
||||
* and collapses the edge on that vertex.
|
||||
*
|
||||
* \par Examples:
|
||||
*
|
||||
* <pre>
|
||||
* Before: e_old e_kill
|
||||
* +-------+-------+
|
||||
* | | |
|
||||
* v_old v_kill v_target
|
||||
*
|
||||
* After: e_old
|
||||
* +---------------+
|
||||
* | |
|
||||
* v_old v_target
|
||||
* </pre>
|
||||
*
|
||||
* \par Restrictions:
|
||||
* KV is a vertex that must have a valance of exactly two. Furthermore
|
||||
* both edges in KV's disk cycle (OE and KE) must be unique (no double edges).
|
||||
*
|
||||
* \return The resulting edge, NULL for failure.
|
||||
*
|
||||
* \note This euler has the possibility of creating
|
||||
* faces with just 2 edges. It is up to the caller to decide what to do with
|
||||
* these faces.
|
||||
*/
|
||||
BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
|
||||
BMEdge *e_kill,
|
||||
BMVert *v_kill,
|
||||
@@ -117,14 +330,83 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
|
||||
const bool check_edge_exists,
|
||||
const bool kill_degenerate_faces,
|
||||
const bool kill_duplicate_faces);
|
||||
/**
|
||||
* \brief Join Vert Kill Edge (JVKE)
|
||||
*
|
||||
* Collapse an edge, merging surrounding data.
|
||||
*
|
||||
* Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert
|
||||
* which only handle 2 valence verts,
|
||||
* this can handle any number of connected edges/faces.
|
||||
*
|
||||
* <pre>
|
||||
* Before: -> After:
|
||||
* +-+-+-+ +-+-+-+
|
||||
* | | | | | \ / |
|
||||
* +-+-+-+ +--+--+
|
||||
* | | | | | / \ |
|
||||
* +-+-+-+ +-+-+-+
|
||||
* </pre>
|
||||
*/
|
||||
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
|
||||
BMEdge *e_kill,
|
||||
BMVert *v_kill,
|
||||
const bool do_del,
|
||||
const bool check_edge_exists,
|
||||
const bool kill_degenerate_faces);
|
||||
/**
|
||||
* \brief Join Face Kill Edge (JFKE)
|
||||
*
|
||||
* Takes two faces joined by a single 2-manifold edge and fuses them together.
|
||||
* The edge shared by the faces must not be connected to any other edges which have
|
||||
* Both faces in its radial cycle
|
||||
*
|
||||
* \par Examples:
|
||||
* <pre>
|
||||
* A B
|
||||
* +--------+ +--------+
|
||||
* | | | |
|
||||
* | f1 | | f1 |
|
||||
* v1========v2 = Ok! v1==V2==v3 == Wrong!
|
||||
* | f2 | | f2 |
|
||||
* | | | |
|
||||
* +--------+ +--------+
|
||||
* </pre>
|
||||
*
|
||||
* In the example A, faces \a f1 and \a f2 are joined by a single edge,
|
||||
* and the euler can safely be used.
|
||||
* In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
|
||||
* The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
|
||||
* before attempting to fuse \a f1 and \a f2.
|
||||
*
|
||||
* \note The order of arguments decides whether or not certain per-face attributes are present
|
||||
* in the resultant face. For instance vertex winding, material index, smooth flags,
|
||||
* etc are inherited from \a f1, not \a f2.
|
||||
*
|
||||
* \return A BMFace pointer
|
||||
*/
|
||||
BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
|
||||
|
||||
/**
|
||||
* \brief Un-glue Region Make Vert (URMV)
|
||||
*
|
||||
* Disconnects a face from its vertex fan at loop \a l_sep
|
||||
*
|
||||
* \return The newly created BMVert
|
||||
*
|
||||
* \note Will be a no-op and return original vertex if only two edges at that vertex.
|
||||
*/
|
||||
BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep);
|
||||
/**
|
||||
* A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
|
||||
* The loops must all share the same vertex, can be in any order
|
||||
* and are all moved to use a single new vertex - which is returned.
|
||||
*
|
||||
* This function handles the details of finding fans boundaries.
|
||||
*/
|
||||
BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len);
|
||||
/**
|
||||
* This function assumes l_sep is a part of a larger fan which has already been
|
||||
* isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
|
||||
*/
|
||||
BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep);
|
||||
|
||||
@@ -99,10 +99,6 @@ void BMO_mesh_delete_oflag_tagged(BMesh *bm, const short oflag, const char htype
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \warning oflag applies to different types in some contexts,
|
||||
* not just the type being removed.
|
||||
*/
|
||||
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
|
||||
{
|
||||
BMEdge *e;
|
||||
@@ -275,10 +271,6 @@ void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \warning oflag applies to different types in some contexts,
|
||||
* not just the type being removed.
|
||||
*/
|
||||
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type)
|
||||
{
|
||||
BMEdge *e;
|
||||
|
||||
@@ -23,5 +23,13 @@
|
||||
void BMO_mesh_delete_oflag_tagged(BMesh *bm, const short oflag, const char htype);
|
||||
void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype);
|
||||
|
||||
/**
|
||||
* \warning oflag applies to different types in some contexts,
|
||||
* not just the type being removed.
|
||||
*/
|
||||
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type);
|
||||
/**
|
||||
* \warning oflag applies to different types in some contexts,
|
||||
* not just the type being removed.
|
||||
*/
|
||||
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type);
|
||||
|
||||
@@ -121,9 +121,6 @@ static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v,
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return listbase of listbases, each linking to a vertex.
|
||||
*/
|
||||
int BM_mesh_edgeloops_find(BMesh *bm,
|
||||
ListBase *r_eloops,
|
||||
bool (*test_fn)(BMEdge *, void *user_data),
|
||||
@@ -506,7 +503,6 @@ void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const boo
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* BM_edgeloop_*** functions */
|
||||
|
||||
/* return new edgeloops */
|
||||
BMEdgeLoopStore *BM_edgeloop_copy(BMEdgeLoopStore *el_store)
|
||||
{
|
||||
BMEdgeLoopStore *el_store_copy = MEM_mallocN(sizeof(*el_store), __func__);
|
||||
@@ -565,9 +561,6 @@ const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store)
|
||||
#define NODE_AS_V(n) ((BMVert *)((LinkData *)n)->data)
|
||||
#define NODE_AS_CO(n) ((BMVert *)((LinkData *)n)->data)->co
|
||||
|
||||
/**
|
||||
* edges are assigned to one vert -> the next.
|
||||
*/
|
||||
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr)
|
||||
{
|
||||
LinkData *node;
|
||||
@@ -653,12 +646,6 @@ bool BM_edgeloop_calc_normal(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For open loops that are straight lines,
|
||||
* calculating the normal as if it were a polygon is meaningless.
|
||||
*
|
||||
* Instead use an alignment vector and calculate the normal based on that.
|
||||
*/
|
||||
bool BM_edgeloop_calc_normal_aligned(BMesh *UNUSED(bm),
|
||||
BMEdgeLoopStore *el_store,
|
||||
const float no_align[3])
|
||||
|
||||
@@ -28,6 +28,9 @@ struct GSet;
|
||||
struct ListBase;
|
||||
|
||||
/* multiple edgeloops (ListBase) */
|
||||
/**
|
||||
* \return listbase of listbases, each linking to a vertex.
|
||||
*/
|
||||
int BM_mesh_edgeloops_find(BMesh *bm,
|
||||
struct ListBase *r_eloops,
|
||||
bool (*test_fn)(BMEdge *, void *user_data),
|
||||
@@ -47,7 +50,10 @@ void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm,
|
||||
const float no_align[3]);
|
||||
void BM_mesh_edgeloops_calc_order(BMesh *bm, ListBase *eloops, const bool use_normals);
|
||||
|
||||
/* single edgeloop */
|
||||
/**
|
||||
* Copy a single edge-loop.
|
||||
* \return new edge-loops.
|
||||
*/
|
||||
struct BMEdgeLoopStore *BM_edgeloop_copy(struct BMEdgeLoopStore *el_store);
|
||||
struct BMEdgeLoopStore *BM_edgeloop_from_verts(BMVert **v_arr,
|
||||
const int v_arr_tot,
|
||||
@@ -59,9 +65,18 @@ int BM_edgeloop_length_get(struct BMEdgeLoopStore *el_store);
|
||||
struct ListBase *BM_edgeloop_verts_get(struct BMEdgeLoopStore *el_store);
|
||||
const float *BM_edgeloop_normal_get(struct BMEdgeLoopStore *el_store);
|
||||
const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store);
|
||||
/**
|
||||
* Edges are assigned to one vert -> the next.
|
||||
*/
|
||||
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr);
|
||||
void BM_edgeloop_calc_center(BMesh *bm, struct BMEdgeLoopStore *el_store);
|
||||
bool BM_edgeloop_calc_normal(BMesh *bm, struct BMEdgeLoopStore *el_store);
|
||||
/**
|
||||
* For open loops that are straight lines,
|
||||
* calculating the normal as if it were a polygon is meaningless.
|
||||
*
|
||||
* Instead use an alignment vector and calculate the normal based on that.
|
||||
*/
|
||||
bool BM_edgeloop_calc_normal_aligned(BMesh *bm,
|
||||
struct BMEdgeLoopStore *el_store,
|
||||
const float no_align[3]);
|
||||
|
||||
@@ -48,13 +48,17 @@ typedef enum eBMOpErrorLevel {
|
||||
BMO_ERROR_FATAL = 2,
|
||||
} eBMOpErrorLevel;
|
||||
|
||||
/* Pushes an error onto the bmesh error stack.
|
||||
* if msg is null, then the default message for the `errcode` is used. */
|
||||
/**
|
||||
* Pushes an error onto the bmesh error stack.
|
||||
* if msg is null, then the default message for the `errcode` is used.
|
||||
*/
|
||||
void BMO_error_raise(BMesh *bm, BMOperator *owner, eBMOpErrorLevel level, const char *msg)
|
||||
ATTR_NONNULL(1, 2, 4);
|
||||
|
||||
/* Gets the topmost error from the stack.
|
||||
* returns error code or 0 if no error. */
|
||||
/**
|
||||
* Gets the topmost error from the stack.
|
||||
* returns error code or 0 if no error.
|
||||
*/
|
||||
bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level);
|
||||
bool BMO_error_get_at_level(BMesh *bm,
|
||||
eBMOpErrorLevel level,
|
||||
@@ -83,8 +87,10 @@ void BMO_error_clear(BMesh *bm);
|
||||
# define _BMESH_DUMMY_ABORT() (void)0
|
||||
#endif
|
||||
|
||||
/* This is meant to be higher level than BLI_assert(),
|
||||
* its enabled even when in Release mode. */
|
||||
/**
|
||||
* This is meant to be higher level than BLI_assert(),
|
||||
* its enabled even when in Release mode.
|
||||
*/
|
||||
#define BMESH_ASSERT(a) \
|
||||
(void)((!(a)) ? ((fprintf(stderr, \
|
||||
"BMESH_ASSERT failed: %s, %s(), %d at \'%s\'\n", \
|
||||
|
||||
@@ -81,13 +81,6 @@ static void bm_data_interp_from_elem(CustomData *data_layer,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Data, Interp From Verts
|
||||
*
|
||||
* Interpolates per-vertex data from two sources to \a v_dst
|
||||
*
|
||||
* \note This is an exact match to #BM_data_interp_from_edges
|
||||
*/
|
||||
void BM_data_interp_from_verts(
|
||||
BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
|
||||
{
|
||||
@@ -95,13 +88,6 @@ void BM_data_interp_from_verts(
|
||||
&bm->vdata, (const BMElem *)v_src_1, (const BMElem *)v_src_2, (BMElem *)v_dst, fac);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Data, Interp From Edges
|
||||
*
|
||||
* Interpolates per-edge data from two sources to \a e_dst.
|
||||
*
|
||||
* \note This is an exact match to #BM_data_interp_from_verts
|
||||
*/
|
||||
void BM_data_interp_from_edges(
|
||||
BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac)
|
||||
{
|
||||
@@ -120,12 +106,6 @@ static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh *UNUSED(bm), BMFace *UNU
|
||||
// BMIter iter;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Data Face-Vert Edge Interp
|
||||
*
|
||||
* Walks around the faces of \a e and interpolates
|
||||
* the loop data between two sources.
|
||||
*/
|
||||
void BM_data_interp_face_vert_edge(BMesh *bm,
|
||||
const BMVert *v_src_1,
|
||||
const BMVert *UNUSED(v_src_2),
|
||||
@@ -169,14 +149,6 @@ void BM_data_interp_face_vert_edge(BMesh *bm,
|
||||
} while ((l_iter = l_iter->radial_next) != e->l);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Data Interp From Face
|
||||
*
|
||||
* projects target onto source, and pulls interpolated customdata from
|
||||
* source.
|
||||
*
|
||||
* \note Only handles loop customdata. multires is handled.
|
||||
*/
|
||||
void BM_face_interp_from_face_ex(BMesh *bm,
|
||||
BMFace *f_dst,
|
||||
const BMFace *f_src,
|
||||
@@ -570,9 +542,6 @@ void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
|
||||
BLI_task_parallel_range(0, res, &data, loop_interp_multires_cb, &settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* project the multires grid in target onto f_src's set of multires grids
|
||||
*/
|
||||
void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
|
||||
{
|
||||
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
|
||||
@@ -618,10 +587,6 @@ void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* smooths boundaries between multires grids,
|
||||
* including some borders in adjacent faces
|
||||
*/
|
||||
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
|
||||
{
|
||||
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
|
||||
@@ -730,10 +695,6 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* projects a single loop, target, onto f_src for customdata interpolation. multires is handled.
|
||||
* if do_vertex is true, target's vert data will also get interpolated.
|
||||
*/
|
||||
void BM_loop_interp_from_face(
|
||||
BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires)
|
||||
{
|
||||
@@ -1246,9 +1207,6 @@ static void bm_vert_loop_groups_data_layer_merge_weights__single(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take existing custom data and merge each fan's data.
|
||||
*/
|
||||
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int layer_n)
|
||||
{
|
||||
const int type = bm->ldata.layers[layer_n].type;
|
||||
@@ -1260,10 +1218,6 @@ void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int
|
||||
} while ((groups = groups->next));
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #BM_vert_loop_groups_data_layer_merge
|
||||
* that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator)
|
||||
*/
|
||||
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
|
||||
LinkNode *groups,
|
||||
const int layer_n,
|
||||
|
||||
@@ -29,6 +29,9 @@ void BM_loop_interp_multires_ex(BMesh *bm,
|
||||
const float f_dst_center[3],
|
||||
const float f_src_center[3],
|
||||
const int cd_loop_mdisp_offset);
|
||||
/**
|
||||
* Project the multi-resolution grid in target onto f_src's set of multi-resolution grids.
|
||||
*/
|
||||
void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src);
|
||||
|
||||
void BM_face_interp_multires_ex(BMesh *bm,
|
||||
@@ -41,10 +44,30 @@ void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src);
|
||||
|
||||
void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src);
|
||||
|
||||
/**
|
||||
* \brief Data, Interpolate From Verts
|
||||
*
|
||||
* Interpolates per-vertex data from two sources to \a v_dst
|
||||
*
|
||||
* \note This is an exact match to #BM_data_interp_from_edges.
|
||||
*/
|
||||
void BM_data_interp_from_verts(
|
||||
BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac);
|
||||
/**
|
||||
* \brief Data, Interpolate From Edges
|
||||
*
|
||||
* Interpolates per-edge data from two sources to \a e_dst.
|
||||
*
|
||||
* \note This is an exact match to #BM_data_interp_from_verts.
|
||||
*/
|
||||
void BM_data_interp_from_edges(
|
||||
BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac);
|
||||
/**
|
||||
* \brief Data Face-Vert Edge Interpolate
|
||||
*
|
||||
* Walks around the faces of \a e and interpolates
|
||||
* the loop data between two sources.
|
||||
*/
|
||||
void BM_data_interp_face_vert_edge(BMesh *bm,
|
||||
const BMVert *v_src_1,
|
||||
const BMVert *v_src_2,
|
||||
@@ -60,6 +83,13 @@ void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int ds
|
||||
float BM_elem_float_data_get(CustomData *cd, void *element, int type);
|
||||
void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val);
|
||||
|
||||
/**
|
||||
* \brief Data Interpolate From Face
|
||||
*
|
||||
* Projects target onto source, and pulls interpolated custom-data from source.
|
||||
*
|
||||
* \note Only handles loop custom-data. multi-res is handled.
|
||||
*/
|
||||
void BM_face_interp_from_face_ex(BMesh *bm,
|
||||
BMFace *f_dst,
|
||||
const BMFace *f_src,
|
||||
@@ -69,14 +99,30 @@ void BM_face_interp_from_face_ex(BMesh *bm,
|
||||
float (*cos_2d)[2],
|
||||
float axis_mat[3][3]);
|
||||
void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex);
|
||||
/**
|
||||
* Projects a single loop, target, onto f_src for custom-data interpolation.
|
||||
* multi-resolution is handled.
|
||||
* \param do_vertex: When true the target's vert data will also get interpolated.
|
||||
*/
|
||||
void BM_loop_interp_from_face(
|
||||
BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires);
|
||||
|
||||
/**
|
||||
* Smooths boundaries between multi-res grids,
|
||||
* including some borders in adjacent faces.
|
||||
*/
|
||||
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f);
|
||||
|
||||
struct LinkNode *BM_vert_loop_groups_data_layer_create(
|
||||
BMesh *bm, BMVert *v, const int layer_n, const float *loop_weights, struct MemArena *arena);
|
||||
/**
|
||||
* Take existing custom data and merge each fan's data.
|
||||
*/
|
||||
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, struct LinkNode *groups, const int layer_n);
|
||||
/**
|
||||
* A version of #BM_vert_loop_groups_data_layer_merge
|
||||
* that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator).
|
||||
*/
|
||||
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
|
||||
struct LinkNode *groups,
|
||||
const int layer_n,
|
||||
|
||||
@@ -47,9 +47,6 @@ const char bm_iter_itype_htype_map[BM_ITYPE_MAX] = {
|
||||
BM_LOOP, /* BM_LOOPS_OF_EDGE */
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility function.
|
||||
*/
|
||||
int BM_iter_mesh_count(const char itype, BMesh *bm)
|
||||
{
|
||||
int count;
|
||||
@@ -73,9 +70,6 @@ int BM_iter_mesh_count(const char itype, BMesh *bm)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
|
||||
*/
|
||||
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
|
||||
{
|
||||
BMIter iter;
|
||||
@@ -98,12 +92,6 @@ void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Iterator as Array
|
||||
*
|
||||
* Sometimes its convenient to get the iterator as an array
|
||||
* to avoid multiple calls to #BM_iter_at_index.
|
||||
*/
|
||||
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -124,11 +112,6 @@ int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, cons
|
||||
|
||||
return i;
|
||||
}
|
||||
/**
|
||||
* \brief Operator Iterator as Array
|
||||
*
|
||||
* Sometimes its convenient to get the iterator as an array.
|
||||
*/
|
||||
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
const char restrictmask,
|
||||
@@ -155,16 +138,6 @@ int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Iterator as Array
|
||||
*
|
||||
* Allocates a new array, has the advantage that you don't need to know the size ahead of time.
|
||||
*
|
||||
* Takes advantage of less common iterator usage to avoid counting twice,
|
||||
* which you might end up doing when #BM_iter_as_array is used.
|
||||
*
|
||||
* Caller needs to free the array.
|
||||
*/
|
||||
void *BM_iter_as_arrayN(BMesh *bm,
|
||||
const char itype,
|
||||
void *data,
|
||||
@@ -272,9 +245,6 @@ int BM_iter_mesh_bitmap_from_filter(const char itype,
|
||||
return bitmap_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Needed when we want to check faces, but return a loop aligned array.
|
||||
*/
|
||||
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
|
||||
BLI_bitmap *bitmap,
|
||||
bool (*test_fn)(BMFace *, void *user_data),
|
||||
@@ -305,11 +275,6 @@ int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
|
||||
return bitmap_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Elem Iter Flag Count
|
||||
*
|
||||
* Counts how many flagged / unflagged items are found in this element.
|
||||
*/
|
||||
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
|
||||
{
|
||||
BMIter iter;
|
||||
@@ -325,11 +290,6 @@ int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, cons
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Elem Iter Tool Flag Count
|
||||
*
|
||||
* Counts how many flagged / unflagged items are found in this element.
|
||||
*/
|
||||
int BMO_iter_elem_count_flag(
|
||||
BMesh *bm, const char itype, void *data, const short oflag, const bool value)
|
||||
{
|
||||
@@ -371,11 +331,6 @@ int BMO_iter_elem_count_flag(
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Mesh Iter Flag Count
|
||||
*
|
||||
* Counts how many flagged / unflagged items are found in this mesh.
|
||||
*/
|
||||
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
|
||||
{
|
||||
BMIter iter;
|
||||
|
||||
@@ -34,13 +34,6 @@
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_mempool.h"
|
||||
|
||||
/* Defines for passing to BM_iter_new.
|
||||
*
|
||||
* "OF" can be substituted for "around"
|
||||
* so BM_VERTS_OF_FACE means "vertices
|
||||
* around a face."
|
||||
*/
|
||||
|
||||
/* these iterator over all elements of a specific
|
||||
* type in the mesh.
|
||||
*
|
||||
@@ -75,6 +68,12 @@ typedef enum BMIterType {
|
||||
/* the iterator htype for each iterator */
|
||||
extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Defines for passing to #BM_iter_new.
|
||||
*
|
||||
* "OF" can be substituted for "around" so #BM_VERTS_OF_FACE means "vertices* around a face."
|
||||
* \{ */
|
||||
|
||||
#define BM_ITER_MESH(ele, iter, bm, itype) \
|
||||
for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, bm, itype, NULL); ele; \
|
||||
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter))
|
||||
@@ -108,6 +107,8 @@ extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
|
||||
for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, NULL, itype, data), indexvar = 0; ele; \
|
||||
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* iterator type structs */
|
||||
struct BMIter__elem_of_mesh {
|
||||
BLI_mempool_iter pooliter;
|
||||
@@ -184,14 +185,38 @@ typedef struct BMIter {
|
||||
char itype;
|
||||
} BMIter;
|
||||
|
||||
/**
|
||||
* \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
|
||||
*/
|
||||
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* \brief Iterator as Array
|
||||
*
|
||||
* Sometimes its convenient to get the iterator as an array
|
||||
* to avoid multiple calls to #BM_iter_at_index.
|
||||
*/
|
||||
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len);
|
||||
/**
|
||||
* \brief Iterator as Array
|
||||
*
|
||||
* Allocates a new array, has the advantage that you don't need to know the size ahead of time.
|
||||
*
|
||||
* Takes advantage of less common iterator usage to avoid counting twice,
|
||||
* which you might end up doing when #BM_iter_as_array is used.
|
||||
*
|
||||
* Caller needs to free the array.
|
||||
*/
|
||||
void *BM_iter_as_arrayN(BMesh *bm,
|
||||
const char itype,
|
||||
void *data,
|
||||
int *r_len,
|
||||
void **stack_array,
|
||||
int stack_array_size) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* \brief Operator Iterator as Array
|
||||
*
|
||||
* Sometimes its convenient to get the iterator as an array.
|
||||
*/
|
||||
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
const char restrictmask,
|
||||
@@ -210,15 +235,36 @@ int BM_iter_mesh_bitmap_from_filter(const char itype,
|
||||
uint *bitmap,
|
||||
bool (*test_fn)(BMElem *, void *user_data),
|
||||
void *user_data);
|
||||
/**
|
||||
* Needed when we want to check faces, but return a loop aligned array.
|
||||
*/
|
||||
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
|
||||
uint *bitmap,
|
||||
bool (*test_fn)(BMFace *, void *user_data),
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* \brief Elem Iter Flag Count
|
||||
*
|
||||
* Counts how many flagged / unflagged items are found in this element.
|
||||
*/
|
||||
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value);
|
||||
/**
|
||||
* \brief Elem Iter Tool Flag Count
|
||||
*
|
||||
* Counts how many flagged / unflagged items are found in this element.
|
||||
*/
|
||||
int BMO_iter_elem_count_flag(
|
||||
BMesh *bm, const char itype, void *data, const short oflag, const bool value);
|
||||
/**
|
||||
* Utility function.
|
||||
*/
|
||||
int BM_iter_mesh_count(const char itype, BMesh *bm);
|
||||
/**
|
||||
* \brief Mesh Iter Flag Count
|
||||
*
|
||||
* Counts how many flagged / unflagged items are found in this mesh.
|
||||
*/
|
||||
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value);
|
||||
|
||||
/* private for bmesh_iterators_inline.c */
|
||||
|
||||
@@ -468,7 +468,6 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
|
||||
|
||||
/***************************** Public API *****************************/
|
||||
|
||||
/* Allocate, initialize, and assign a new BMLog */
|
||||
BMLog *BM_log_create(BMesh *bm)
|
||||
{
|
||||
BMLog *log = MEM_callocN(sizeof(*log), __func__);
|
||||
@@ -506,14 +505,6 @@ void BM_log_cleanup_entry(BMLogEntry *entry)
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate and initialize a new BMLog using existing BMLogEntries
|
||||
*
|
||||
* The 'entry' should be the last entry in the BMLog. Its prev pointer
|
||||
* will be followed back to find the first entry.
|
||||
*
|
||||
* The unused IDs field of the log will be initialized by taking all
|
||||
* keys from all GHashes in the log entry.
|
||||
*/
|
||||
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
|
||||
{
|
||||
BMLog *log = BM_log_create(bm);
|
||||
@@ -555,7 +546,6 @@ BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
|
||||
return log;
|
||||
}
|
||||
|
||||
/* Free all the data in a BMLog including the log itself */
|
||||
void BM_log_free(BMLog *log)
|
||||
{
|
||||
BMLogEntry *entry;
|
||||
@@ -581,13 +571,11 @@ void BM_log_free(BMLog *log)
|
||||
MEM_freeN(log);
|
||||
}
|
||||
|
||||
/* Get the number of log entries */
|
||||
int BM_log_length(const BMLog *log)
|
||||
{
|
||||
return BLI_listbase_count(&log->entries);
|
||||
}
|
||||
|
||||
/* Apply a consistent ordering to BMesh vertices */
|
||||
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
|
||||
{
|
||||
uint *varr;
|
||||
@@ -639,16 +627,6 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
|
||||
MEM_freeN(farr);
|
||||
}
|
||||
|
||||
/* Start a new log entry and update the log entry list
|
||||
*
|
||||
* If the log entry list is empty, or if the current log entry is the
|
||||
* last entry, the new entry is simply appended to the end.
|
||||
*
|
||||
* Otherwise, the new entry is added after the current entry and all
|
||||
* following entries are deleted.
|
||||
*
|
||||
* In either case, the new entry is set as the current log entry.
|
||||
*/
|
||||
BMLogEntry *BM_log_entry_add(BMLog *log)
|
||||
{
|
||||
/* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT
|
||||
@@ -676,15 +654,6 @@ BMLogEntry *BM_log_entry_add(BMLog *log)
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Remove an entry from the log
|
||||
*
|
||||
* Uses entry->log as the log. If the log is NULL, the entry will be
|
||||
* free'd but not removed from any list, nor shall its IDs be
|
||||
* released.
|
||||
*
|
||||
* This operation is only valid on the first and last entries in the
|
||||
* log. Deleting from the middle will assert.
|
||||
*/
|
||||
void BM_log_entry_drop(BMLogEntry *entry)
|
||||
{
|
||||
BMLog *log = entry->log;
|
||||
@@ -751,9 +720,6 @@ void BM_log_entry_drop(BMLogEntry *entry)
|
||||
BLI_freelinkN(&log->entries, entry);
|
||||
}
|
||||
|
||||
/* Undo one BMLogEntry
|
||||
*
|
||||
* Has no effect if there's nothing left to undo */
|
||||
void BM_log_undo(BMesh *bm, BMLog *log)
|
||||
{
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
@@ -775,9 +741,6 @@ void BM_log_undo(BMesh *bm, BMLog *log)
|
||||
}
|
||||
}
|
||||
|
||||
/* Redo one BMLogEntry
|
||||
*
|
||||
* Has no effect if there's nothing left to redo */
|
||||
void BM_log_redo(BMesh *bm, BMLog *log)
|
||||
{
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
@@ -812,29 +775,6 @@ void BM_log_redo(BMesh *bm, BMLog *log)
|
||||
}
|
||||
}
|
||||
|
||||
/* Log a vertex before it is modified
|
||||
*
|
||||
* Before modifying vertex coordinates, masks, or hflags, call this
|
||||
* function to log its current values. This is better than logging
|
||||
* after the coordinates have been modified, because only those
|
||||
* vertices that are modified need to have their original values
|
||||
* stored.
|
||||
*
|
||||
* Handles two separate cases:
|
||||
*
|
||||
* If the vertex was added in the current log entry, update the
|
||||
* vertex in the map of added vertices.
|
||||
*
|
||||
* If the vertex already existed prior to the current log entry, a
|
||||
* separate key/value map of modified vertices is used (using the
|
||||
* vertex's ID as the key). The values stored in that case are
|
||||
* the vertex's original state so that an undo can restore the
|
||||
* previous state.
|
||||
*
|
||||
* On undo, the current vertex state will be swapped with the stored
|
||||
* state so that a subsequent redo operation will restore the newer
|
||||
* vertex state.
|
||||
*/
|
||||
void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
|
||||
{
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
@@ -853,12 +793,6 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
|
||||
}
|
||||
}
|
||||
|
||||
/* Log a new vertex as added to the BMesh
|
||||
*
|
||||
* The new vertex gets a unique ID assigned. It is then added to a map
|
||||
* of added vertices, with the key being its ID and the value
|
||||
* containing everything needed to reconstruct that vertex.
|
||||
*/
|
||||
void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
|
||||
{
|
||||
BMLogVert *lv;
|
||||
@@ -870,11 +804,6 @@ void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
|
||||
BLI_ghash_insert(log->current_entry->added_verts, key, lv);
|
||||
}
|
||||
|
||||
/* Log a face before it is modified
|
||||
*
|
||||
* This is intended to handle only header flags and we always
|
||||
* assume face has been added before
|
||||
*/
|
||||
void BM_log_face_modified(BMLog *log, BMFace *f)
|
||||
{
|
||||
BMLogFace *lf;
|
||||
@@ -885,12 +814,6 @@ void BM_log_face_modified(BMLog *log, BMFace *f)
|
||||
BLI_ghash_insert(log->current_entry->modified_faces, key, lf);
|
||||
}
|
||||
|
||||
/* Log a new face as added to the BMesh
|
||||
*
|
||||
* The new face gets a unique ID assigned. It is then added to a map
|
||||
* of added faces, with the key being its ID and the value containing
|
||||
* everything needed to reconstruct that face.
|
||||
*/
|
||||
void BM_log_face_added(BMLog *log, BMFace *f)
|
||||
{
|
||||
BMLogFace *lf;
|
||||
@@ -905,22 +828,6 @@ void BM_log_face_added(BMLog *log, BMFace *f)
|
||||
BLI_ghash_insert(log->current_entry->added_faces, key, lf);
|
||||
}
|
||||
|
||||
/* Log a vertex as removed from the BMesh
|
||||
*
|
||||
* A couple things can happen here:
|
||||
*
|
||||
* If the vertex was added as part of the current log entry, then it's
|
||||
* deleted and forgotten about entirely. Its unique ID is returned to
|
||||
* the unused pool.
|
||||
*
|
||||
* If the vertex was already part of the BMesh before the current log
|
||||
* entry, it is added to a map of deleted vertices, with the key being
|
||||
* its ID and the value containing everything needed to reconstruct
|
||||
* that vertex.
|
||||
*
|
||||
* If there's a move record for the vertex, that's used as the
|
||||
* vertices original location, then the move record is deleted.
|
||||
*/
|
||||
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
|
||||
{
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
@@ -949,19 +856,6 @@ void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
|
||||
}
|
||||
}
|
||||
|
||||
/* Log a face as removed from the BMesh
|
||||
*
|
||||
* A couple things can happen here:
|
||||
*
|
||||
* If the face was added as part of the current log entry, then it's
|
||||
* deleted and forgotten about entirely. Its unique ID is returned to
|
||||
* the unused pool.
|
||||
*
|
||||
* If the face was already part of the BMesh before the current log
|
||||
* entry, it is added to a map of deleted faces, with the key being
|
||||
* its ID and the value containing everything needed to reconstruct
|
||||
* that face.
|
||||
*/
|
||||
void BM_log_face_removed(BMLog *log, BMFace *f)
|
||||
{
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
@@ -983,7 +877,6 @@ void BM_log_face_removed(BMLog *log, BMFace *f)
|
||||
}
|
||||
}
|
||||
|
||||
/* Log all vertices/faces in the BMesh as added */
|
||||
void BM_log_all_added(BMesh *bm, BMLog *log)
|
||||
{
|
||||
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
|
||||
@@ -1011,7 +904,6 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
|
||||
}
|
||||
}
|
||||
|
||||
/* Log all vertices/faces in the BMesh as removed */
|
||||
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
|
||||
{
|
||||
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
|
||||
@@ -1030,9 +922,6 @@ void BM_log_before_all_removed(BMesh *bm, BMLog *log)
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the logged coordinates of a vertex
|
||||
*
|
||||
* Does not modify the log or the vertex */
|
||||
const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
|
||||
{
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
@@ -1048,9 +937,6 @@ const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
|
||||
return lv->co;
|
||||
}
|
||||
|
||||
/* Get the logged normal of a vertex
|
||||
*
|
||||
* Does not modify the log or the vertex */
|
||||
const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
|
||||
{
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
@@ -1066,9 +952,6 @@ const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
|
||||
return lv->no;
|
||||
}
|
||||
|
||||
/* Get the logged mask of a vertex
|
||||
*
|
||||
* Does not modify the log or the vertex */
|
||||
float BM_log_original_mask(BMLog *log, BMVert *v)
|
||||
{
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
@@ -1102,13 +985,11 @@ void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const
|
||||
|
||||
/************************ Debugging and Testing ***********************/
|
||||
|
||||
/* For internal use only (unit testing) */
|
||||
BMLogEntry *BM_log_current_entry(BMLog *log)
|
||||
{
|
||||
return log->current_entry;
|
||||
}
|
||||
|
||||
/* For internal use only (unit testing) */
|
||||
RangeTreeUInt *BM_log_unused_ids(BMLog *log)
|
||||
{
|
||||
return log->unused_ids;
|
||||
|
||||
@@ -29,71 +29,190 @@ typedef struct BMLog BMLog;
|
||||
typedef struct BMLogEntry BMLogEntry;
|
||||
|
||||
/* Allocate and initialize a new BMLog */
|
||||
/* Allocate, initialize, and assign a new BMLog */
|
||||
BMLog *BM_log_create(BMesh *bm);
|
||||
|
||||
/* Allocate and initialize a new BMLog using existing BMLogEntries */
|
||||
/* Allocate and initialize a new BMLog using existing BMLogEntries
|
||||
*
|
||||
* The 'entry' should be the last entry in the BMLog. Its prev pointer
|
||||
* will be followed back to find the first entry.
|
||||
*
|
||||
* The unused IDs field of the log will be initialized by taking all
|
||||
* keys from all GHashes in the log entry.
|
||||
*/
|
||||
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry);
|
||||
|
||||
/* Free all the data in a BMLog including the log itself */
|
||||
/* Free all the data in a BMLog including the log itself */
|
||||
void BM_log_free(BMLog *log);
|
||||
|
||||
/* Get the number of log entries */
|
||||
/* Get the number of log entries */
|
||||
int BM_log_length(const BMLog *log);
|
||||
|
||||
/* Apply a consistent ordering to BMesh vertices and faces */
|
||||
/* Apply a consistent ordering to BMesh vertices */
|
||||
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log);
|
||||
|
||||
/* Start a new log entry and update the log entry list */
|
||||
/* Start a new log entry and update the log entry list
|
||||
*
|
||||
* If the log entry list is empty, or if the current log entry is the
|
||||
* last entry, the new entry is simply appended to the end.
|
||||
*
|
||||
* Otherwise, the new entry is added after the current entry and all
|
||||
* following entries are deleted.
|
||||
*
|
||||
* In either case, the new entry is set as the current log entry.
|
||||
*/
|
||||
BMLogEntry *BM_log_entry_add(BMLog *log);
|
||||
|
||||
/* Mark all used ids as unused for this node */
|
||||
void BM_log_cleanup_entry(BMLogEntry *entry);
|
||||
|
||||
/* Remove an entry from the log */
|
||||
/* Remove an entry from the log
|
||||
*
|
||||
* Uses entry->log as the log. If the log is NULL, the entry will be
|
||||
* free'd but not removed from any list, nor shall its IDs be
|
||||
* released.
|
||||
*
|
||||
* This operation is only valid on the first and last entries in the
|
||||
* log. Deleting from the middle will assert.
|
||||
*/
|
||||
void BM_log_entry_drop(BMLogEntry *entry);
|
||||
|
||||
/* Undo one BMLogEntry */
|
||||
/* Undo one BMLogEntry
|
||||
*
|
||||
* Has no effect if there's nothing left to undo */
|
||||
void BM_log_undo(BMesh *bm, BMLog *log);
|
||||
|
||||
/* Redo one BMLogEntry */
|
||||
/* Redo one BMLogEntry
|
||||
*
|
||||
* Has no effect if there's nothing left to redo */
|
||||
void BM_log_redo(BMesh *bm, BMLog *log);
|
||||
|
||||
/* Log a vertex before it is modified */
|
||||
/* Log a vertex before it is modified
|
||||
*
|
||||
* Before modifying vertex coordinates, masks, or hflags, call this
|
||||
* function to log its current values. This is better than logging
|
||||
* after the coordinates have been modified, because only those
|
||||
* vertices that are modified need to have their original values
|
||||
* stored.
|
||||
*
|
||||
* Handles two separate cases:
|
||||
*
|
||||
* If the vertex was added in the current log entry, update the
|
||||
* vertex in the map of added vertices.
|
||||
*
|
||||
* If the vertex already existed prior to the current log entry, a
|
||||
* separate key/value map of modified vertices is used (using the
|
||||
* vertex's ID as the key). The values stored in that case are
|
||||
* the vertex's original state so that an undo can restore the
|
||||
* previous state.
|
||||
*
|
||||
* On undo, the current vertex state will be swapped with the stored
|
||||
* state so that a subsequent redo operation will restore the newer
|
||||
* vertex state.
|
||||
*/
|
||||
void BM_log_vert_before_modified(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
|
||||
|
||||
/* Log a new vertex as added to the BMesh */
|
||||
/* Log a new vertex as added to the BMesh
|
||||
*
|
||||
* The new vertex gets a unique ID assigned. It is then added to a map
|
||||
* of added vertices, with the key being its ID and the value
|
||||
* containing everything needed to reconstruct that vertex.
|
||||
*/
|
||||
void BM_log_vert_added(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
|
||||
|
||||
/* Log a face before it is modified */
|
||||
/* Log a face before it is modified
|
||||
*
|
||||
* This is intended to handle only header flags and we always
|
||||
* assume face has been added before
|
||||
*/
|
||||
void BM_log_face_modified(BMLog *log, struct BMFace *f);
|
||||
|
||||
/* Log a new face as added to the BMesh */
|
||||
/* Log a new face as added to the BMesh
|
||||
*
|
||||
* The new face gets a unique ID assigned. It is then added to a map
|
||||
* of added faces, with the key being its ID and the value containing
|
||||
* everything needed to reconstruct that face.
|
||||
*/
|
||||
void BM_log_face_added(BMLog *log, struct BMFace *f);
|
||||
|
||||
/* Log a vertex as removed from the BMesh */
|
||||
/* Log a vertex as removed from the BMesh
|
||||
*
|
||||
* A couple things can happen here:
|
||||
*
|
||||
* If the vertex was added as part of the current log entry, then it's
|
||||
* deleted and forgotten about entirely. Its unique ID is returned to
|
||||
* the unused pool.
|
||||
*
|
||||
* If the vertex was already part of the BMesh before the current log
|
||||
* entry, it is added to a map of deleted vertices, with the key being
|
||||
* its ID and the value containing everything needed to reconstruct
|
||||
* that vertex.
|
||||
*
|
||||
* If there's a move record for the vertex, that's used as the
|
||||
* vertices original location, then the move record is deleted.
|
||||
*/
|
||||
void BM_log_vert_removed(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
|
||||
|
||||
/* Log a face as removed from the BMesh */
|
||||
/* Log a face as removed from the BMesh
|
||||
*
|
||||
* A couple things can happen here:
|
||||
*
|
||||
* If the face was added as part of the current log entry, then it's
|
||||
* deleted and forgotten about entirely. Its unique ID is returned to
|
||||
* the unused pool.
|
||||
*
|
||||
* If the face was already part of the BMesh before the current log
|
||||
* entry, it is added to a map of deleted faces, with the key being
|
||||
* its ID and the value containing everything needed to reconstruct
|
||||
* that face.
|
||||
*/
|
||||
void BM_log_face_removed(BMLog *log, struct BMFace *f);
|
||||
|
||||
/* Log all vertices/faces in the BMesh as added */
|
||||
/* Log all vertices/faces in the BMesh as added */
|
||||
void BM_log_all_added(BMesh *bm, BMLog *log);
|
||||
|
||||
/* Log all vertices/faces in the BMesh as removed */
|
||||
/* Log all vertices/faces in the BMesh as removed */
|
||||
void BM_log_before_all_removed(BMesh *bm, BMLog *log);
|
||||
|
||||
/* Get the logged coordinates of a vertex */
|
||||
/* Get the logged coordinates of a vertex
|
||||
*
|
||||
* Does not modify the log or the vertex */
|
||||
const float *BM_log_original_vert_co(BMLog *log, BMVert *v);
|
||||
|
||||
/* Get the logged normal of a vertex */
|
||||
/* Get the logged normal of a vertex
|
||||
*
|
||||
* Does not modify the log or the vertex */
|
||||
const short *BM_log_original_vert_no(BMLog *log, BMVert *v);
|
||||
|
||||
/* Get the logged mask of a vertex */
|
||||
/* Get the logged mask of a vertex
|
||||
*
|
||||
* Does not modify the log or the vertex */
|
||||
float BM_log_original_mask(BMLog *log, BMVert *v);
|
||||
|
||||
/* Get the logged data of a vertex (avoid multiple lookups) */
|
||||
void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const short **r_no);
|
||||
|
||||
/* For internal use only (unit testing) */
|
||||
/* For internal use only (unit testing) */
|
||||
BMLogEntry *BM_log_current_entry(BMLog *log);
|
||||
/* For internal use only (unit testing) */
|
||||
struct RangeTreeUInt *BM_log_unused_ids(BMLog *log);
|
||||
|
||||
@@ -251,14 +251,6 @@ static bool bm_edge_is_face_visible_any(const BMEdge *e)
|
||||
|
||||
/** \} */
|
||||
|
||||
/**
|
||||
* \brief Select Mode Clean
|
||||
*
|
||||
* Remove isolated selected elements when in a mode doesn't support them.
|
||||
* eg: in edge-mode a selected vertex must be connected to a selected edge.
|
||||
*
|
||||
* \note this could be made a part of #BM_mesh_select_mode_flush_ex
|
||||
*/
|
||||
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
|
||||
{
|
||||
if (selectmode & SCE_SELECT_VERTEX) {
|
||||
@@ -424,13 +416,6 @@ static void bm_mesh_select_mode_flush_edge_to_face(BMesh *bm)
|
||||
bm->totfacesel += chunk_data.delta_selection_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Select Mode Flush
|
||||
*
|
||||
* Makes sure to flush selections 'upwards'
|
||||
* (ie: all verts of an edge selects the edge and so on).
|
||||
* This should only be called by system and not tool authors.
|
||||
*/
|
||||
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
|
||||
{
|
||||
if (selectmode & SCE_SELECT_VERTEX) {
|
||||
@@ -463,9 +448,6 @@ void BM_mesh_select_mode_flush(BMesh *bm)
|
||||
|
||||
/** \} */
|
||||
|
||||
/**
|
||||
* mode independent flushing up/down
|
||||
*/
|
||||
void BM_mesh_deselect_flush(BMesh *bm)
|
||||
{
|
||||
BMIter eiter;
|
||||
@@ -498,9 +480,6 @@ void BM_mesh_deselect_flush(BMesh *bm)
|
||||
recount_totsels(bm);
|
||||
}
|
||||
|
||||
/**
|
||||
* mode independent flushing up/down
|
||||
*/
|
||||
void BM_mesh_select_flush(BMesh *bm)
|
||||
{
|
||||
BMEdge *e;
|
||||
@@ -542,12 +521,6 @@ void BM_mesh_select_flush(BMesh *bm)
|
||||
recount_totsels(bm);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Select Vert
|
||||
*
|
||||
* Changes selection state of a single vertex
|
||||
* in a mesh
|
||||
*/
|
||||
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
|
||||
{
|
||||
BLI_assert(v->head.htype == BM_VERT);
|
||||
@@ -570,11 +543,6 @@ void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Select Edge
|
||||
*
|
||||
* Changes selection state of a single edge in a mesh.
|
||||
*/
|
||||
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
|
||||
{
|
||||
BLI_assert(e->head.htype == BM_EDGE);
|
||||
@@ -615,12 +583,6 @@ void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Select Face
|
||||
*
|
||||
* Changes selection state of a single
|
||||
* face in a mesh.
|
||||
*/
|
||||
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
|
||||
{
|
||||
BMLoop *l_iter;
|
||||
@@ -746,12 +708,6 @@ void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select)
|
||||
|
||||
/** \} */
|
||||
|
||||
/**
|
||||
* Select Mode Set
|
||||
*
|
||||
* Sets the selection mode for the bmesh,
|
||||
* updating the selection state.
|
||||
*/
|
||||
void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
|
||||
{
|
||||
BMIter iter;
|
||||
@@ -867,10 +823,6 @@ int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
|
||||
return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
|
||||
* \note by design, this will not touch the editselection history stuff
|
||||
*/
|
||||
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
|
||||
{
|
||||
switch (ele->head.htype) {
|
||||
@@ -889,7 +841,6 @@ void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
|
||||
}
|
||||
}
|
||||
|
||||
/* this replaces the active flag used in uv/face mode */
|
||||
void BM_mesh_active_face_set(BMesh *bm, BMFace *f)
|
||||
{
|
||||
bm->act_face = f;
|
||||
@@ -974,15 +925,6 @@ BMElem *BM_mesh_active_elem_get(BMesh *bm)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic way to get data from an EditSelection type
|
||||
* These functions were written to be used by the Modifier widget
|
||||
* when in Rotate about active mode, but can be used anywhere.
|
||||
*
|
||||
* - #BM_editselection_center
|
||||
* - #BM_editselection_normal
|
||||
* - #BM_editselection_plane
|
||||
*/
|
||||
void BM_editselection_center(BMEditSelection *ese, float r_center[3])
|
||||
{
|
||||
if (ese->htype == BM_VERT) {
|
||||
@@ -1027,11 +969,6 @@ void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a plane that is right angles to the edge/vert/faces normal
|
||||
* also make the plane run along an axis that is related to the geometry,
|
||||
* because this is used for the gizmos Y axis.
|
||||
*/
|
||||
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
|
||||
{
|
||||
if (ese->htype == BM_VERT) {
|
||||
@@ -1098,6 +1035,7 @@ static BMEditSelection *bm_select_history_create(BMHeader *ele)
|
||||
}
|
||||
|
||||
/* --- macro wrapped funcs --- */
|
||||
|
||||
bool _bm_select_history_check(BMesh *bm, const BMHeader *ele)
|
||||
{
|
||||
return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != NULL);
|
||||
@@ -1170,9 +1108,6 @@ void BM_select_history_validate(BMesh *bm)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active mesh element (with active-face fallback).
|
||||
*/
|
||||
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
|
||||
{
|
||||
BMEditSelection *ese_last = bm->selected.last;
|
||||
@@ -1209,9 +1144,6 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map from BMVert/Edge/Face -> BMEditSelection
|
||||
*/
|
||||
GHash *BM_select_history_map_create(BMesh *bm)
|
||||
{
|
||||
BMEditSelection *ese;
|
||||
@@ -1230,9 +1162,6 @@ GHash *BM_select_history_map_create(BMesh *bm)
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map arguments may all be the same pointer.
|
||||
*/
|
||||
void BM_select_history_merge_from_targetmap(
|
||||
BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
|
||||
{
|
||||
|
||||
@@ -36,14 +36,20 @@ typedef enum eBMSelectionFlushFLags {
|
||||
BM_SELECT_LEN_FLUSH_RECALC_FACE),
|
||||
} eBMSelectionFlushFLags;
|
||||
|
||||
/* geometry hiding code */
|
||||
/* Geometry hiding code. */
|
||||
|
||||
#define BM_elem_hide_set(bm, ele, hide) _bm_elem_hide_set(bm, &(ele)->head, hide)
|
||||
void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide);
|
||||
void BM_vert_hide_set(BMVert *v, const bool hide);
|
||||
void BM_edge_hide_set(BMEdge *e, const bool hide);
|
||||
void BM_face_hide_set(BMFace *f, const bool hide);
|
||||
|
||||
/* Selection code */
|
||||
/* Selection code. */
|
||||
|
||||
/**
|
||||
* \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
|
||||
* \note by design, this will not touch the editselection history stuff
|
||||
*/
|
||||
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select);
|
||||
|
||||
void BM_mesh_elem_hflag_enable_test(BMesh *bm,
|
||||
@@ -68,24 +74,70 @@ void BM_mesh_elem_hflag_disable_all(BMesh *bm,
|
||||
const char hflag,
|
||||
const bool respecthide);
|
||||
|
||||
/* Individual element select functions, BM_elem_select_set is a shortcut for these
|
||||
/* Individual element select functions, #BM_elem_select_set is a shortcut for these
|
||||
* that automatically detects which one to use. */
|
||||
|
||||
/**
|
||||
* \brief Select Vert
|
||||
*
|
||||
* Changes selection state of a single vertex
|
||||
* in a mesh
|
||||
*/
|
||||
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select);
|
||||
/**
|
||||
* \brief Select Edge
|
||||
*
|
||||
* Changes selection state of a single edge in a mesh.
|
||||
*/
|
||||
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select);
|
||||
/**
|
||||
* \brief Select Face
|
||||
*
|
||||
* Changes selection state of a single
|
||||
* face in a mesh.
|
||||
*/
|
||||
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select);
|
||||
|
||||
/* lower level functions which don't do flushing */
|
||||
/* Lower level functions which don't do flushing. */
|
||||
|
||||
void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, const bool select);
|
||||
void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select);
|
||||
|
||||
/**
|
||||
* \brief Select Mode Clean
|
||||
*
|
||||
* Remove isolated selected elements when in a mode doesn't support them.
|
||||
* eg: in edge-mode a selected vertex must be connected to a selected edge.
|
||||
*
|
||||
* \note this could be made a part of #BM_mesh_select_mode_flush_ex
|
||||
*/
|
||||
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode);
|
||||
void BM_mesh_select_mode_clean(BMesh *bm);
|
||||
|
||||
/**
|
||||
* Select Mode Set
|
||||
*
|
||||
* Sets the selection mode for the bmesh,
|
||||
* updating the selection state.
|
||||
*/
|
||||
void BM_mesh_select_mode_set(BMesh *bm, int selectmode);
|
||||
/**
|
||||
* \brief Select Mode Flush
|
||||
*
|
||||
* Makes sure to flush selections 'upwards'
|
||||
* (ie: all verts of an edge selects the edge and so on).
|
||||
* This should only be called by system and not tool authors.
|
||||
*/
|
||||
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags);
|
||||
void BM_mesh_select_mode_flush(BMesh *bm);
|
||||
|
||||
/**
|
||||
* Mode independent de-selection flush (up/down).
|
||||
*/
|
||||
void BM_mesh_deselect_flush(BMesh *bm);
|
||||
/**
|
||||
* Mode independent selection flush (up/down).
|
||||
*/
|
||||
void BM_mesh_select_flush(BMesh *bm);
|
||||
|
||||
int BM_mesh_elem_hflag_count_enabled(BMesh *bm,
|
||||
@@ -97,15 +149,30 @@ int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
|
||||
const char hflag,
|
||||
const bool respecthide);
|
||||
|
||||
/* edit selection stuff */
|
||||
/* Edit selection stuff. */
|
||||
|
||||
void BM_mesh_active_face_set(BMesh *bm, BMFace *f);
|
||||
BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected);
|
||||
BMEdge *BM_mesh_active_edge_get(BMesh *bm);
|
||||
BMVert *BM_mesh_active_vert_get(BMesh *bm);
|
||||
BMElem *BM_mesh_active_elem_get(BMesh *bm);
|
||||
|
||||
/**
|
||||
* Generic way to get data from an #BMEditSelection type
|
||||
* These functions were written to be used by the Modifier widget
|
||||
* when in Rotate about active mode, but can be used anywhere.
|
||||
*
|
||||
* - #BM_editselection_center
|
||||
* - #BM_editselection_normal
|
||||
* - #BM_editselection_plane
|
||||
*/
|
||||
void BM_editselection_center(BMEditSelection *ese, float r_center[3]);
|
||||
void BM_editselection_normal(BMEditSelection *ese, float r_normal[3]);
|
||||
/**
|
||||
* Calculate a plane that is right angles to the edge/vert/faces normal
|
||||
* also make the plane run along an axis that is related to the geometry,
|
||||
* because this is used for the gizmos Y axis.
|
||||
*/
|
||||
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]);
|
||||
|
||||
#define BM_select_history_check(bm, ele) _bm_select_history_check(bm, &(ele)->head)
|
||||
@@ -131,9 +198,18 @@ void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref,
|
||||
|
||||
void BM_select_history_validate(BMesh *bm);
|
||||
void BM_select_history_clear(BMesh *bm);
|
||||
/**
|
||||
* Get the active mesh element (with active-face fallback).
|
||||
*/
|
||||
bool BM_select_history_active_get(BMesh *bm, struct BMEditSelection *ese);
|
||||
/**
|
||||
* Return a map from #BMVert/#BMEdge/#BMFace -> #BMEditSelection.
|
||||
*/
|
||||
struct GHash *BM_select_history_map_create(BMesh *bm);
|
||||
|
||||
/**
|
||||
* Map arguments may all be the same pointer.
|
||||
*/
|
||||
void BM_select_history_merge_from_targetmap(
|
||||
BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain);
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
/* used as an extern, defined in bmesh.h */
|
||||
const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
|
||||
const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
|
||||
|
||||
@@ -137,15 +136,6 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMesh Make Mesh
|
||||
*
|
||||
* Allocates a new BMesh structure.
|
||||
*
|
||||
* \return The New bmesh
|
||||
*
|
||||
* \note ob is needed by multires
|
||||
*/
|
||||
BMesh *BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
|
||||
{
|
||||
/* allocate the structure */
|
||||
@@ -167,13 +157,6 @@ BMesh *BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreate
|
||||
return bm;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMesh Free Mesh Data
|
||||
*
|
||||
* Frees a BMesh structure.
|
||||
*
|
||||
* \note frees mesh, but not actual BMesh struct
|
||||
*/
|
||||
void BM_mesh_data_free(BMesh *bm)
|
||||
{
|
||||
BMVert *v;
|
||||
@@ -265,11 +248,6 @@ void BM_mesh_data_free(BMesh *bm)
|
||||
BMO_error_clear(bm);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMesh Clear Mesh
|
||||
*
|
||||
* Clear all data in bm
|
||||
*/
|
||||
void BM_mesh_clear(BMesh *bm)
|
||||
{
|
||||
const bool use_toolflags = bm->use_toolflags;
|
||||
@@ -291,11 +269,6 @@ void BM_mesh_clear(BMesh *bm)
|
||||
CustomData_reset(&bm->pdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMesh Free Mesh
|
||||
*
|
||||
* Frees a BMesh data and its structure.
|
||||
*/
|
||||
void BM_mesh_free(BMesh *bm)
|
||||
{
|
||||
BM_mesh_data_free(bm);
|
||||
@@ -310,13 +283,6 @@ void BM_mesh_free(BMesh *bm)
|
||||
MEM_freeN(bm);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMesh Begin Edit
|
||||
*
|
||||
* Functions for setting up a mesh for editing and cleaning up after
|
||||
* the editing operations are done. These are called by the tools/operator
|
||||
* API for each time a tool is executed.
|
||||
*/
|
||||
void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
|
||||
{
|
||||
/* Most operators seem to be using BMO_OPTYPE_FLAG_UNTAN_MULTIRES to change the MDisps to
|
||||
@@ -337,9 +303,6 @@ void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMesh End Edit
|
||||
*/
|
||||
void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
|
||||
{
|
||||
ListBase select_history;
|
||||
@@ -499,18 +462,6 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
|
||||
BM_mesh_elem_index_ensure_ex(bm, htype, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Array checking/setting macros
|
||||
*
|
||||
* Currently vert/edge/loop/face index data is being abused, in a few areas of the code.
|
||||
*
|
||||
* To avoid correcting them afterwards, set 'bm->elem_index_dirty' however its possible
|
||||
* this flag is set incorrectly which could crash blender.
|
||||
*
|
||||
* Code that calls this functions may depend on dirty indices on being set.
|
||||
* Keep this function read-only.
|
||||
*/
|
||||
|
||||
void BM_mesh_elem_index_validate(
|
||||
BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b)
|
||||
{
|
||||
@@ -693,7 +644,6 @@ finally:
|
||||
bm->elem_table_dirty &= ~htype_needed;
|
||||
}
|
||||
|
||||
/* use BM_mesh_elem_table_ensure where possible to avoid full rebuild */
|
||||
void BM_mesh_elem_table_init(BMesh *bm, const char htype)
|
||||
{
|
||||
BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
|
||||
@@ -754,11 +704,6 @@ BMLoop *BM_loop_at_index_find(BMesh *bm, const int index)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use lookup table when available, else use slower find functions.
|
||||
*
|
||||
* \note Try to use #BM_mesh_elem_table_ensure instead.
|
||||
*/
|
||||
BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index)
|
||||
{
|
||||
if ((bm->elem_table_dirty & BM_VERT) == 0) {
|
||||
@@ -783,9 +728,6 @@ BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index)
|
||||
return BM_face_at_index_find(bm, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the amount of element of type 'type' in a given bmesh.
|
||||
*/
|
||||
int BM_mesh_elem_count(BMesh *bm, const char htype)
|
||||
{
|
||||
BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
|
||||
@@ -804,20 +746,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
|
||||
* (xxx_idx[org_index] = new_index).
|
||||
*
|
||||
* A NULL array means no changes.
|
||||
*
|
||||
* \note
|
||||
* - Does not mess with indices, just sets elem_index_dirty flag.
|
||||
* - For verts/edges/faces only (as loops must remain "ordered" and "aligned"
|
||||
* on a per-face basis...).
|
||||
*
|
||||
* \warning Be careful if you keep pointers to affected BM elements,
|
||||
* or arrays, when using this func!
|
||||
*/
|
||||
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
|
||||
{
|
||||
/* Mapping old to new pointers. */
|
||||
@@ -1106,12 +1034,6 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use new memory pools for this mesh.
|
||||
*
|
||||
* \note needed for re-sizing elements (adding/removing tool flags)
|
||||
* but could also be used for packing fragmented bmeshes.
|
||||
*/
|
||||
void BM_mesh_rebuild(BMesh *bm,
|
||||
const struct BMeshCreateParams *params,
|
||||
BLI_mempool *vpool_dst,
|
||||
@@ -1363,9 +1285,6 @@ void BM_mesh_rebuild(BMesh *bm,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-allocates mesh data with/without toolflags.
|
||||
*/
|
||||
void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
|
||||
{
|
||||
if (bm->use_toolflags == use_toolflags) {
|
||||
|
||||
@@ -34,28 +34,83 @@ struct BMeshCreateParams {
|
||||
uint use_toolflags : 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief BMesh Make Mesh
|
||||
*
|
||||
* Allocates a new BMesh structure.
|
||||
*
|
||||
* \return The New bmesh
|
||||
*
|
||||
* \note ob is needed by multires
|
||||
*/
|
||||
BMesh *BM_mesh_create(const struct BMAllocTemplate *allocsize,
|
||||
const struct BMeshCreateParams *params);
|
||||
|
||||
/**
|
||||
* \brief BMesh Free Mesh
|
||||
*
|
||||
* Frees a BMesh data and its structure.
|
||||
*/
|
||||
void BM_mesh_free(BMesh *bm);
|
||||
/**
|
||||
* \brief BMesh Free Mesh Data
|
||||
*
|
||||
* Frees a BMesh structure.
|
||||
*
|
||||
* \note frees mesh, but not actual BMesh struct
|
||||
*/
|
||||
void BM_mesh_data_free(BMesh *bm);
|
||||
/**
|
||||
* \brief BMesh Clear Mesh
|
||||
*
|
||||
* Clear all data in bm
|
||||
*/
|
||||
void BM_mesh_clear(BMesh *bm);
|
||||
|
||||
/**
|
||||
* \brief BMesh Begin Edit
|
||||
*
|
||||
* Functions for setting up a mesh for editing and cleaning up after
|
||||
* the editing operations are done. These are called by the tools/operator
|
||||
* API for each time a tool is executed.
|
||||
*/
|
||||
void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
|
||||
/**
|
||||
* \brief BMesh End Edit
|
||||
*/
|
||||
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
|
||||
|
||||
void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4]);
|
||||
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype);
|
||||
/**
|
||||
* Array checking/setting macros.
|
||||
*
|
||||
* Currently vert/edge/loop/face index data is being abused, in a few areas of the code.
|
||||
*
|
||||
* To avoid correcting them afterwards, set 'bm->elem_index_dirty' however its possible
|
||||
* this flag is set incorrectly which could crash blender.
|
||||
*
|
||||
* Functions that calls this function may depend on dirty indices on being set.
|
||||
*
|
||||
* This is read-only, so it can be used for assertions that don't impact behavior.
|
||||
*/
|
||||
void BM_mesh_elem_index_validate(
|
||||
BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b);
|
||||
|
||||
void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
|
||||
|
||||
#ifndef NDEBUG
|
||||
/**
|
||||
* \see #BM_mesh_elem_index_validate the same rationale applies to this function.
|
||||
*/
|
||||
bool BM_mesh_elem_table_check(BMesh *bm);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Re-allocates mesh data with/without toolflags.
|
||||
*/
|
||||
void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
|
||||
|
||||
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype);
|
||||
/* use BM_mesh_elem_table_ensure where possible to avoid full rebuild */
|
||||
void BM_mesh_elem_table_init(BMesh *bm, const char htype);
|
||||
void BM_mesh_elem_table_free(BMesh *bm, const char htype);
|
||||
|
||||
@@ -83,16 +138,44 @@ BMEdge *BM_edge_at_index_find(BMesh *bm, const int index);
|
||||
BMFace *BM_face_at_index_find(BMesh *bm, const int index);
|
||||
BMLoop *BM_loop_at_index_find(BMesh *bm, const int index);
|
||||
|
||||
/**
|
||||
* Use lookup table when available, else use slower find functions.
|
||||
*
|
||||
* \note Try to use #BM_mesh_elem_table_ensure instead.
|
||||
*/
|
||||
BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index);
|
||||
BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index);
|
||||
BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index);
|
||||
|
||||
// XXX
|
||||
|
||||
/**
|
||||
* Return the amount of element of type 'type' in a given bmesh.
|
||||
*/
|
||||
int BM_mesh_elem_count(BMesh *bm, const char htype);
|
||||
|
||||
/**
|
||||
* Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
|
||||
* (xxx_idx[org_index] = new_index).
|
||||
*
|
||||
* A NULL array means no changes.
|
||||
*
|
||||
* \note
|
||||
* - Does not mess with indices, just sets elem_index_dirty flag.
|
||||
* - For verts/edges/faces only (as loops must remain "ordered" and "aligned"
|
||||
* on a per-face basis...).
|
||||
*
|
||||
* \warning Be careful if you keep pointers to affected BM elements,
|
||||
* or arrays, when using this func!
|
||||
*/
|
||||
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx);
|
||||
|
||||
/**
|
||||
* Use new memory pools for this mesh.
|
||||
*
|
||||
* \note needed for re-sizing elements (adding/removing tool flags)
|
||||
* but could also be used for packing fragmented bmeshes.
|
||||
*/
|
||||
void BM_mesh_rebuild(BMesh *bm,
|
||||
const struct BMeshCreateParams *params,
|
||||
struct BLI_mempool *vpool,
|
||||
@@ -104,6 +187,7 @@ typedef struct BMAllocTemplate {
|
||||
int totvert, totedge, totloop, totface;
|
||||
} BMAllocTemplate;
|
||||
|
||||
/* used as an extern, defined in bmesh.h */
|
||||
extern const BMAllocTemplate bm_mesh_allocsize_default;
|
||||
extern const BMAllocTemplate bm_mesh_chunksize_default;
|
||||
|
||||
|
||||
@@ -176,16 +176,6 @@ static BMFace *bm_face_create_from_mpoly(
|
||||
return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Mesh -> BMesh
|
||||
* \param bm: The mesh to write into, while this is typically a newly created BMesh,
|
||||
* merging into existing data is supported.
|
||||
* Note the custom-data layout isn't used.
|
||||
* If more comprehensive merging is needed we should move this into a separate function
|
||||
* since this should be kept fast for edit-mode switching and storing undo steps.
|
||||
*
|
||||
* \warning This function doesn't calculate face normals.
|
||||
*/
|
||||
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
|
||||
{
|
||||
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
|
||||
@@ -582,10 +572,6 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
|
||||
*/
|
||||
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
|
||||
{
|
||||
MEdge *med;
|
||||
@@ -1005,23 +991,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
||||
BKE_mesh_runtime_clear_geometry(me);
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #BM_mesh_bm_to_me intended for getting the mesh
|
||||
* to pass to the modifier stack for evaluation,
|
||||
* instead of mode switching (where we make sure all data is kept
|
||||
* and do expensive lookups to maintain shape keys).
|
||||
*
|
||||
* Key differences:
|
||||
*
|
||||
* - Don't support merging with existing mesh.
|
||||
* - Ignore shape-keys.
|
||||
* - Ignore vertex-parents.
|
||||
* - Ignore selection history.
|
||||
* - Uses simpler method to calculate #ME_EDGEDRAW
|
||||
* - Uses #CD_MASK_DERIVEDMESH instead of #CD_MASK_MESH.
|
||||
*
|
||||
* \note Was `cddm_from_bmesh_ex` in 2.7x, removed `MFace` support.
|
||||
*/
|
||||
void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra)
|
||||
{
|
||||
/* Must be an empty mesh. */
|
||||
|
||||
@@ -43,6 +43,16 @@ struct BMeshFromMeshParams {
|
||||
int active_shapekey;
|
||||
struct CustomData_MeshMasks cd_mask_extra;
|
||||
};
|
||||
/**
|
||||
* \brief Mesh -> BMesh
|
||||
* \param bm: The mesh to write into, while this is typically a newly created BMesh,
|
||||
* merging into existing data is supported.
|
||||
* Note the custom-data layout isn't used.
|
||||
* If more comprehensive merging is needed we should move this into a separate function
|
||||
* since this should be kept fast for edit-mode switching and storing undo steps.
|
||||
*
|
||||
* \warning This function doesn't calculate face normals.
|
||||
*/
|
||||
void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFromMeshParams *params)
|
||||
ATTR_NONNULL(1, 3);
|
||||
|
||||
@@ -61,11 +71,32 @@ struct BMeshToMeshParams {
|
||||
uint update_shapekey_indices : 1;
|
||||
struct CustomData_MeshMasks cd_mask_extra;
|
||||
};
|
||||
/**
|
||||
*
|
||||
* \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
|
||||
*/
|
||||
void BM_mesh_bm_to_me(struct Main *bmain,
|
||||
BMesh *bm,
|
||||
struct Mesh *me,
|
||||
const struct BMeshToMeshParams *params) ATTR_NONNULL(2, 3, 4);
|
||||
|
||||
/**
|
||||
* A version of #BM_mesh_bm_to_me intended for getting the mesh
|
||||
* to pass to the modifier stack for evaluation,
|
||||
* instead of mode switching (where we make sure all data is kept
|
||||
* and do expensive lookups to maintain shape keys).
|
||||
*
|
||||
* Key differences:
|
||||
*
|
||||
* - Don't support merging with existing mesh.
|
||||
* - Ignore shape-keys.
|
||||
* - Ignore vertex-parents.
|
||||
* - Ignore selection history.
|
||||
* - Uses simpler method to calculate #ME_EDGEDRAW
|
||||
* - Uses #CD_MASK_DERIVEDMESH instead of #CD_MASK_MESH.
|
||||
*
|
||||
* \note Was `cddm_from_bmesh_ex` in 2.7x, removed `MFace` support.
|
||||
*/
|
||||
void BM_mesh_bm_to_me_for_eval(BMesh *bm,
|
||||
struct Mesh *me,
|
||||
const struct CustomData_MeshMasks *cd_mask_extra)
|
||||
|
||||
@@ -85,9 +85,6 @@ static BMFace *bm_face_copy_with_arrays(
|
||||
return f_dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Geometry must be completely isolated.
|
||||
*/
|
||||
void BM_mesh_copy_arrays(BMesh *bm_src,
|
||||
BMesh *bm_dst,
|
||||
BMVert **verts_src,
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Geometry must be completely isolated.
|
||||
*/
|
||||
void BM_mesh_copy_arrays(BMesh *bm_src,
|
||||
BMesh *bm_dst,
|
||||
BMVert **verts_src,
|
||||
|
||||
@@ -247,11 +247,6 @@ static void bm_face_calc_normals_cb(void *UNUSED(userdata),
|
||||
BM_face_calc_normal(f, f->no);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMesh Compute Normals
|
||||
*
|
||||
* Updates the normals of a mesh.
|
||||
*/
|
||||
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params)
|
||||
{
|
||||
if (params->face_normals) {
|
||||
@@ -295,10 +290,6 @@ static void bm_partial_verts_parallel_range_calc_normal_cb(
|
||||
bm_vert_calc_normals_impl(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #BM_mesh_normals_update that updates a subset of geometry,
|
||||
* used to avoid the overhead of updating everything.
|
||||
*/
|
||||
void BM_mesh_normals_update_with_partial_ex(BMesh *UNUSED(bm),
|
||||
const BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshNormalsUpdate_Params *params)
|
||||
@@ -343,12 +334,6 @@ void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpin
|
||||
/** \name Update Vertex & Face Normals (Custom Coords)
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \brief BMesh Compute Normals from/to external data.
|
||||
*
|
||||
* Computes the vertex normals of a mesh into vnos,
|
||||
* using given vertex coordinates (vcos) and polygon normals (fnos).
|
||||
*/
|
||||
void BM_verts_calc_normal_vcos(BMesh *bm,
|
||||
const float (*fnos)[3],
|
||||
const float (*vcos)[3],
|
||||
@@ -435,12 +420,6 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm,
|
||||
bm->elem_index_dirty &= ~BM_EDGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
|
||||
*
|
||||
* Used when defining an empty custom loop normals data layer,
|
||||
* to keep same shading as with auto-smooth!
|
||||
*/
|
||||
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
|
||||
{
|
||||
if (split_angle >= (float)M_PI) {
|
||||
@@ -457,11 +436,6 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
|
||||
/** \name Loop Normals Calculation API
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
|
||||
* Needed because cyclic smooth fans have no obvious 'entry point',
|
||||
* and yet we need to walk them once, and only once.
|
||||
*/
|
||||
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
|
||||
{
|
||||
BMLoop *lfan_pivot_next = l_curr;
|
||||
@@ -1720,13 +1694,6 @@ static void bm_mesh_loops_calc_normals_no_autosmooth(BMesh *bm,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMesh Compute Loop Normals from/to external data.
|
||||
*
|
||||
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
|
||||
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
|
||||
* (splitting edges).
|
||||
*/
|
||||
void BM_loops_calc_normal_vcos(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*vnos)[3],
|
||||
@@ -1933,10 +1900,6 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
|
||||
* take care to run this before setting up tags.
|
||||
*/
|
||||
void BM_lnorspace_update(BMesh *bm)
|
||||
{
|
||||
if (bm->lnor_spacearr == NULL) {
|
||||
@@ -2250,10 +2213,6 @@ void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
|
||||
/** \name Custom Normals / Vector Layer Conversion
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
|
||||
* take care to run this before setting up tags.
|
||||
*/
|
||||
bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
|
||||
{
|
||||
BMFace *f;
|
||||
|
||||
@@ -30,17 +30,39 @@ struct BMeshNormalsUpdate_Params {
|
||||
bool face_normals;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief BMesh Compute Normals
|
||||
*
|
||||
* Updates the normals of a mesh.
|
||||
*/
|
||||
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *param);
|
||||
void BM_mesh_normals_update(BMesh *bm);
|
||||
/**
|
||||
* A version of #BM_mesh_normals_update that updates a subset of geometry,
|
||||
* used to avoid the overhead of updating everything.
|
||||
*/
|
||||
void BM_mesh_normals_update_with_partial_ex(BMesh *bm,
|
||||
const struct BMPartialUpdate *bmpinfo,
|
||||
const struct BMeshNormalsUpdate_Params *param);
|
||||
void BM_mesh_normals_update_with_partial(BMesh *bm, const struct BMPartialUpdate *bmpinfo);
|
||||
|
||||
/**
|
||||
* \brief BMesh Compute Normals from/to external data.
|
||||
*
|
||||
* Computes the vertex normals of a mesh into vnos,
|
||||
* using given vertex coordinates (vcos) and polygon normals (fnos).
|
||||
*/
|
||||
void BM_verts_calc_normal_vcos(BMesh *bm,
|
||||
const float (*fnos)[3],
|
||||
const float (*vcos)[3],
|
||||
float (*vnos)[3]);
|
||||
/**
|
||||
* \brief BMesh Compute Loop Normals from/to external data.
|
||||
*
|
||||
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
|
||||
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
|
||||
* (splitting edges).
|
||||
*/
|
||||
void BM_loops_calc_normal_vcos(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*vnos)[3],
|
||||
@@ -53,10 +75,19 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
|
||||
const int cd_loop_clnors_offset,
|
||||
const bool do_rebuild);
|
||||
|
||||
/**
|
||||
* Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
|
||||
* Needed because cyclic smooth fans have no obvious 'entry point',
|
||||
* and yet we need to walk them once, and only once.
|
||||
*/
|
||||
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
|
||||
void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3]);
|
||||
void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all);
|
||||
void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor);
|
||||
/**
|
||||
* \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
|
||||
* take care to run this before setting up tags.
|
||||
*/
|
||||
void BM_lnorspace_update(BMesh *bm);
|
||||
void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges);
|
||||
#ifndef NDEBUG
|
||||
@@ -68,7 +99,17 @@ struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm,
|
||||
const bool do_all_loops_of_vert);
|
||||
void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
|
||||
|
||||
/**
|
||||
* \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
|
||||
* take care to run this before setting up tags.
|
||||
*/
|
||||
bool BM_custom_loop_normals_to_vector_layer(struct BMesh *bm);
|
||||
void BM_custom_loop_normals_from_vector_layer(struct BMesh *bm, bool add_sharp_edges);
|
||||
|
||||
/**
|
||||
* Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
|
||||
*
|
||||
* Used when defining an empty custom loop normals data layer,
|
||||
* to keep same shading as with auto-smooth!
|
||||
*/
|
||||
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
|
||||
|
||||
@@ -103,10 +103,6 @@ BLI_INLINE bool partial_elem_face_ensure(BMPartialUpdate *bmpinfo,
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* All Tagged & Connected, see: #BM_mesh_partial_create_from_verts
|
||||
* Operate on everything that's tagged as well as connected geometry.
|
||||
*/
|
||||
BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
|
||||
const BMPartialUpdate_Params *params,
|
||||
const BLI_bitmap *verts_mask,
|
||||
@@ -216,11 +212,6 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
|
||||
return bmpinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* All Connected, operate on all faces that have both tagged and un-tagged vertices.
|
||||
*
|
||||
* Reduces computations when transforming isolated regions.
|
||||
*/
|
||||
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
|
||||
BMesh *bm,
|
||||
const BMPartialUpdate_Params *params,
|
||||
@@ -314,25 +305,6 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
|
||||
return bmpinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* All Connected, operate on all faces that have vertices in the same group.
|
||||
*
|
||||
* Reduces computations when transforming isolated regions.
|
||||
*
|
||||
* This is a version of #BM_mesh_partial_create_from_verts_group_single
|
||||
* that handles multiple groups instead of a bitmap mask.
|
||||
*
|
||||
* This is needed for example when transform has mirror enabled,
|
||||
* since one side needs to have a different group to the other since a face that has vertices
|
||||
* attached to both won't have an affine transformation.
|
||||
*
|
||||
* \param verts_groups: Vertex aligned array of groups.
|
||||
* Values are used as follows:
|
||||
* - >0: Each face is grouped with other faces of the same group.
|
||||
* - 0: Not in a group (don't handle these).
|
||||
* - -1: Don't use grouping logic (include any face that contains a vertex with this group).
|
||||
* \param verts_groups_count: The number of non-zero values in `verts_groups`.
|
||||
*/
|
||||
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_multi(
|
||||
BMesh *bm,
|
||||
const BMPartialUpdate_Params *params,
|
||||
|
||||
@@ -52,18 +52,46 @@ typedef struct BMPartialUpdate {
|
||||
BMPartialUpdate_Params params;
|
||||
} BMPartialUpdate;
|
||||
|
||||
/**
|
||||
* All Tagged & Connected, see: #BM_mesh_partial_create_from_verts
|
||||
* Operate on everything that's tagged as well as connected geometry.
|
||||
*/
|
||||
BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
|
||||
const BMPartialUpdate_Params *params,
|
||||
const unsigned int *verts_mask,
|
||||
const int verts_mask_count)
|
||||
ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* All Connected, operate on all faces that have both tagged and un-tagged vertices.
|
||||
*
|
||||
* Reduces computations when transforming isolated regions.
|
||||
*/
|
||||
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
|
||||
BMesh *bm,
|
||||
const BMPartialUpdate_Params *params,
|
||||
const unsigned int *verts_mask,
|
||||
const int verts_mask_count) ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* All Connected, operate on all faces that have vertices in the same group.
|
||||
*
|
||||
* Reduces computations when transforming isolated regions.
|
||||
*
|
||||
* This is a version of #BM_mesh_partial_create_from_verts_group_single
|
||||
* that handles multiple groups instead of a bitmap mask.
|
||||
*
|
||||
* This is needed for example when transform has mirror enabled,
|
||||
* since one side needs to have a different group to the other since a face that has vertices
|
||||
* attached to both won't have an affine transformation.
|
||||
*
|
||||
* \param verts_groups: Vertex aligned array of groups.
|
||||
* Values are used as follows:
|
||||
* - >0: Each face is grouped with other faces of the same group.
|
||||
* - 0: Not in a group (don't handle these).
|
||||
* - -1: Don't use grouping logic (include any face that contains a vertex with this group).
|
||||
* \param verts_groups_count: The number of non-zero values in `verts_groups`.
|
||||
*/
|
||||
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_multi(
|
||||
BMesh *bm,
|
||||
const BMPartialUpdate_Params *params,
|
||||
|
||||
@@ -549,9 +549,6 @@ static int bmesh_calc_tessellation_for_face_beauty(BMLoop *(*looptris)[3],
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
|
||||
*/
|
||||
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3])
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
|
||||
@@ -35,6 +35,9 @@ void BM_mesh_calc_tessellation_ex(BMesh *bm,
|
||||
const struct BMeshCalcTessellation_Params *params);
|
||||
void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]);
|
||||
|
||||
/**
|
||||
* A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
|
||||
*/
|
||||
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3]);
|
||||
|
||||
void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm,
|
||||
|
||||
@@ -50,12 +50,6 @@
|
||||
(void)0
|
||||
# endif
|
||||
|
||||
/**
|
||||
* Check of this BMesh is valid,
|
||||
* this function can be slow since its intended to help with debugging.
|
||||
*
|
||||
* \return true when the mesh is valid.
|
||||
*/
|
||||
bool BM_mesh_validate(BMesh *bm)
|
||||
{
|
||||
EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, bm->totedge);
|
||||
|
||||
@@ -23,4 +23,10 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check of this #BMesh is valid,
|
||||
* this function can be slow since its intended to help with debugging.
|
||||
*
|
||||
* \return true when the mesh is valid.
|
||||
*/
|
||||
bool BM_mesh_validate(BMesh *bm);
|
||||
|
||||
@@ -31,31 +31,6 @@
|
||||
#include "bmesh.h"
|
||||
#include "intern/bmesh_private.h"
|
||||
|
||||
/**
|
||||
* \brief Dissolve Vert
|
||||
*
|
||||
* Turns the face region surrounding a manifold vertex into a single polygon.
|
||||
*
|
||||
* \par Example:
|
||||
* <pre>
|
||||
* +---------+ +---------+
|
||||
* | \ / | | |
|
||||
* Before: | v | After: | |
|
||||
* | / \ | | |
|
||||
* +---------+ +---------+
|
||||
* </pre>
|
||||
*
|
||||
* This function can also collapse edges too
|
||||
* in cases when it can't merge into faces.
|
||||
*
|
||||
* \par Example:
|
||||
* <pre>
|
||||
* Before: +----v----+ After: +---------+
|
||||
* </pre>
|
||||
*
|
||||
* \note dissolves vert, in more situations than BM_disk_dissolve
|
||||
* (e.g. if the vert is part of a wire edge, etc).
|
||||
*/
|
||||
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
|
||||
{
|
||||
/* logic for 3 or more is identical */
|
||||
@@ -87,9 +62,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
|
||||
return BM_disk_dissolve(bm, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* dissolves all faces around a vert, and removes it.
|
||||
*/
|
||||
bool BM_disk_dissolve(BMesh *bm, BMVert *v)
|
||||
{
|
||||
BMEdge *e, *keepedge = NULL, *baseedge = NULL;
|
||||
@@ -205,19 +177,6 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Faces Join Pair
|
||||
*
|
||||
* Joins two adjacent faces together.
|
||||
*
|
||||
* \note This method calls to #BM_faces_join to do its work.
|
||||
* This means connected edges which also share the two faces will be joined.
|
||||
*
|
||||
* If the windings do not match the winding of the new face will follow
|
||||
* \a l_a's winding (i.e. \a l_b will be reversed before the join).
|
||||
*
|
||||
* \return The combined face or NULL on failure.
|
||||
*/
|
||||
BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
|
||||
{
|
||||
BLI_assert((l_a != l_b) && (l_a->e == l_b->e));
|
||||
@@ -231,24 +190,6 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_de
|
||||
return BM_faces_join(bm, faces, 2, do_del);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Face Split
|
||||
*
|
||||
* Split a face along two vertices. returns the newly made face, and sets
|
||||
* the \a r_l member to a loop in the newly created edge.
|
||||
*
|
||||
* \param bm: The bmesh
|
||||
* \param f: the original face
|
||||
* \param l_a, l_b: Loops of this face, their vertices define
|
||||
* the split edge to be created (must be differ and not can't be adjacent in the face).
|
||||
* \param r_l: pointer which will receive the BMLoop for the split edge in the new face
|
||||
* \param example: Edge used for attributes of splitting edge, if non-NULL
|
||||
* \param no_double: Use an existing edge if found
|
||||
*
|
||||
* \return Pointer to the newly created face representing one side of the split
|
||||
* if the split is successful (and the original face will be the other side).
|
||||
* NULL if the split fails.
|
||||
*/
|
||||
BMFace *BM_face_split(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMLoop *l_a,
|
||||
@@ -313,24 +254,6 @@ BMFace *BM_face_split(BMesh *bm,
|
||||
return f_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Face Split with intermediate points
|
||||
*
|
||||
* Like BM_face_split, but with an edge split by \a n intermediate points with given coordinates.
|
||||
*
|
||||
* \param bm: The bmesh.
|
||||
* \param f: the original face.
|
||||
* \param l_a, l_b: Vertices which define the split edge, must be different.
|
||||
* \param cos: Array of coordinates for intermediate points.
|
||||
* \param n: Length of \a cos (must be > 0).
|
||||
* \param r_l: pointer which will receive the BMLoop.
|
||||
* for the first split edge (from \a l_a) in the new face.
|
||||
* \param example: Edge used for attributes of splitting edge, if non-NULL.
|
||||
*
|
||||
* \return Pointer to the newly created face representing one side of the split
|
||||
* if the split is successful (and the original face will be the other side).
|
||||
* NULL if the split fails.
|
||||
*/
|
||||
BMFace *BM_face_split_n(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMLoop *l_a,
|
||||
@@ -404,29 +327,6 @@ BMFace *BM_face_split_n(BMesh *bm,
|
||||
return f_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Vert Collapse Faces
|
||||
*
|
||||
* Collapses vertex \a v_kill that has only two manifold edges
|
||||
* onto a vertex it shares an edge with.
|
||||
* \a fac defines the amount of interpolation for Custom Data.
|
||||
*
|
||||
* \note that this is not a general edge collapse function.
|
||||
*
|
||||
* \note this function is very close to #BM_vert_collapse_edge,
|
||||
* both collapse a vertex and return a new edge.
|
||||
* Except this takes a factor and merges custom data.
|
||||
*
|
||||
* \param bm: The bmesh
|
||||
* \param e_kill: The edge to collapse
|
||||
* \param v_kill: The vertex to collapse into the edge
|
||||
* \param fac: The factor along the edge
|
||||
* \param join_faces: When true the faces around the vertex will be joined
|
||||
* otherwise collapse the vertex by merging the 2 edges this vert touches into one.
|
||||
* \param kill_degenerate_faces: Removes faces with less than 3 verts after collapsing.
|
||||
*
|
||||
* \returns The New Edge
|
||||
*/
|
||||
BMEdge *BM_vert_collapse_faces(BMesh *bm,
|
||||
BMEdge *e_kill,
|
||||
BMVert *v_kill,
|
||||
@@ -513,13 +413,6 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm,
|
||||
return e_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Vert Collapse Faces
|
||||
*
|
||||
* Collapses a vertex onto another vertex it shares an edge with.
|
||||
*
|
||||
* \return The New Edge
|
||||
*/
|
||||
BMEdge *BM_vert_collapse_edge(BMesh *bm,
|
||||
BMEdge *e_kill,
|
||||
BMVert *v_kill,
|
||||
@@ -560,34 +453,12 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm,
|
||||
|
||||
#undef DO_V_INTERP
|
||||
|
||||
/**
|
||||
* Collapse and edge into a single vertex.
|
||||
*/
|
||||
BMVert *BM_edge_collapse(
|
||||
BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
|
||||
{
|
||||
return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Edge Split
|
||||
*
|
||||
* <pre>
|
||||
* Before: v
|
||||
* +-----------------------------------+
|
||||
* e
|
||||
*
|
||||
* After: v v_new (returned)
|
||||
* +-----------------+-----------------+
|
||||
* r_e e
|
||||
* </pre>
|
||||
*
|
||||
* \param e: The edge to split.
|
||||
* \param v: One of the vertices in \a e and defines the "from" end of the splitting operation,
|
||||
* the new vertex will be \a fac of the way from \a v to the other end.
|
||||
* \param r_e: The newly created edge.
|
||||
* \return The new vertex.
|
||||
*/
|
||||
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
|
||||
{
|
||||
BMVert *v_new, *v_other;
|
||||
@@ -703,11 +574,6 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
|
||||
return v_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Split an edge multiple times evenly
|
||||
*
|
||||
* \param r_varr: Optional array, verts in between (v1 -> v2)
|
||||
*/
|
||||
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
|
||||
{
|
||||
int i;
|
||||
@@ -725,11 +591,6 @@ BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
|
||||
return v_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap v1 & v2
|
||||
*
|
||||
* \note Typically we shouldn't care about this, however it's used when extruding wire edges.
|
||||
*/
|
||||
void BM_edge_verts_swap(BMEdge *e)
|
||||
{
|
||||
SWAP(BMVert *, e->v1, e->v2);
|
||||
@@ -785,20 +646,6 @@ bool BM_face_validate(BMFace *face, FILE *err)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Calculate the 2 loops which _would_ make up the newly rotated Edge
|
||||
* but don't actually change anything.
|
||||
*
|
||||
* Use this to further inspect if the loops to be connected have issues:
|
||||
*
|
||||
* Examples:
|
||||
* - the newly formed edge already exists
|
||||
* - the new face would be degenerate (zero area / concave / bow-tie)
|
||||
* - may want to measure if the new edge gives improved results topology.
|
||||
* over the old one, as with beauty fill.
|
||||
*
|
||||
* \note #BM_edge_rotate_check must have already run.
|
||||
*/
|
||||
void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2)
|
||||
{
|
||||
BMVert *v1, *v2;
|
||||
@@ -825,12 +672,6 @@ void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2
|
||||
*r_l2 = BM_face_other_vert_loop(fa, v1, v2);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if Rotate Edge is OK
|
||||
*
|
||||
* Quick check to see if we could rotate the edge,
|
||||
* use this to avoid calling exceptions on common cases.
|
||||
*/
|
||||
bool BM_edge_rotate_check(BMEdge *e)
|
||||
{
|
||||
BMFace *fa, *fb;
|
||||
@@ -860,17 +701,6 @@ bool BM_edge_rotate_check(BMEdge *e)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if Edge Rotate Gives Degenerate Faces
|
||||
*
|
||||
* Check 2 cases
|
||||
* 1) does the newly forms edge form a flipped face (compare with previous cross product)
|
||||
* 2) does the newly formed edge cause a zero area corner (or close enough to be almost zero)
|
||||
*
|
||||
* \param e: The edge to test rotation.
|
||||
* \param l1, l2: are the loops of the proposed verts to rotate too and should
|
||||
* be the result of calling #BM_edge_calc_rotate
|
||||
*/
|
||||
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2)
|
||||
{
|
||||
/* NOTE: for these vars 'old' just means initial edge state. */
|
||||
@@ -966,20 +796,6 @@ bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2)
|
||||
return (len_squared_v3v3(e->v1->co, e->v2->co) > len_squared_v3v3(l1->v->co, l2->v->co));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Rotate Edge
|
||||
*
|
||||
* Spins an edge topologically,
|
||||
* either counter-clockwise or clockwise depending on \a ccw.
|
||||
*
|
||||
* \return The spun edge, NULL on error
|
||||
* (e.g., if the edge isn't surrounded by exactly two faces).
|
||||
*
|
||||
* \note This works by dissolving the edge then re-creating it,
|
||||
* so the returned edge won't have the same pointer address as the original one.
|
||||
*
|
||||
* \see header definition for \a check_flag enum.
|
||||
*/
|
||||
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
|
||||
{
|
||||
BMVert *v1, *v2;
|
||||
@@ -1091,9 +907,6 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
|
||||
return e_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Rip a single face from a vertex fan
|
||||
*/
|
||||
BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
|
||||
{
|
||||
return bmesh_kernel_unglue_region_make_vert(bm, l_sep);
|
||||
|
||||
@@ -20,14 +20,73 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Dissolve Vert
|
||||
*
|
||||
* Turns the face region surrounding a manifold vertex into a single polygon.
|
||||
*
|
||||
* \par Example:
|
||||
* <pre>
|
||||
* +---------+ +---------+
|
||||
* | \ / | | |
|
||||
* Before: | v | After: | |
|
||||
* | / \ | | |
|
||||
* +---------+ +---------+
|
||||
* </pre>
|
||||
*
|
||||
* This function can also collapse edges too
|
||||
* in cases when it can't merge into faces.
|
||||
*
|
||||
* \par Example:
|
||||
* <pre>
|
||||
* Before: +----v----+ After: +---------+
|
||||
* </pre>
|
||||
*
|
||||
* \note dissolves vert, in more situations than BM_disk_dissolve
|
||||
* (e.g. if the vert is part of a wire edge, etc).
|
||||
*/
|
||||
bool BM_vert_dissolve(BMesh *bm, BMVert *v);
|
||||
|
||||
/**
|
||||
* dissolves all faces around a vert, and removes it.
|
||||
*/
|
||||
bool BM_disk_dissolve(BMesh *bm, BMVert *v);
|
||||
|
||||
/**
|
||||
* \brief Faces Join Pair
|
||||
*
|
||||
* Joins two adjacent faces together.
|
||||
*
|
||||
* \note This method calls to #BM_faces_join to do its work.
|
||||
* This means connected edges which also share the two faces will be joined.
|
||||
*
|
||||
* If the windings do not match the winding of the new face will follow
|
||||
* \a l_a's winding (i.e. \a l_b will be reversed before the join).
|
||||
*
|
||||
* \return The combined face or NULL on failure.
|
||||
*/
|
||||
BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del);
|
||||
|
||||
/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */
|
||||
|
||||
/**
|
||||
* \brief Face Split
|
||||
*
|
||||
* Split a face along two vertices. returns the newly made face, and sets
|
||||
* the \a r_l member to a loop in the newly created edge.
|
||||
*
|
||||
* \param bm: The bmesh
|
||||
* \param f: the original face
|
||||
* \param l_a, l_b: Loops of this face, their vertices define
|
||||
* the split edge to be created (must be differ and not can't be adjacent in the face).
|
||||
* \param r_l: pointer which will receive the BMLoop for the split edge in the new face
|
||||
* \param example: Edge used for attributes of splitting edge, if non-NULL
|
||||
* \param no_double: Use an existing edge if found
|
||||
*
|
||||
* \return Pointer to the newly created face representing one side of the split
|
||||
* if the split is successful (and the original face will be the other side).
|
||||
* NULL if the split fails.
|
||||
*/
|
||||
BMFace *BM_face_split(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMLoop *l_a,
|
||||
@@ -36,6 +95,24 @@ BMFace *BM_face_split(BMesh *bm,
|
||||
BMEdge *example,
|
||||
const bool no_double);
|
||||
|
||||
/**
|
||||
* \brief Face Split with intermediate points
|
||||
*
|
||||
* Like BM_face_split, but with an edge split by \a n intermediate points with given coordinates.
|
||||
*
|
||||
* \param bm: The bmesh.
|
||||
* \param f: the original face.
|
||||
* \param l_a, l_b: Vertices which define the split edge, must be different.
|
||||
* \param cos: Array of coordinates for intermediate points.
|
||||
* \param n: Length of \a cos (must be > 0).
|
||||
* \param r_l: pointer which will receive the BMLoop.
|
||||
* for the first split edge (from \a l_a) in the new face.
|
||||
* \param example: Edge used for attributes of splitting edge, if non-NULL.
|
||||
*
|
||||
* \return Pointer to the newly created face representing one side of the split
|
||||
* if the split is successful (and the original face will be the other side).
|
||||
* NULL if the split fails.
|
||||
*/
|
||||
BMFace *BM_face_split_n(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMLoop *l_a,
|
||||
@@ -45,6 +122,29 @@ BMFace *BM_face_split_n(BMesh *bm,
|
||||
BMLoop **r_l,
|
||||
BMEdge *example);
|
||||
|
||||
/**
|
||||
* \brief Vert Collapse Faces
|
||||
*
|
||||
* Collapses vertex \a v_kill that has only two manifold edges
|
||||
* onto a vertex it shares an edge with.
|
||||
* \a fac defines the amount of interpolation for Custom Data.
|
||||
*
|
||||
* \note that this is not a general edge collapse function.
|
||||
*
|
||||
* \note this function is very close to #BM_vert_collapse_edge,
|
||||
* both collapse a vertex and return a new edge.
|
||||
* Except this takes a factor and merges custom data.
|
||||
*
|
||||
* \param bm: The bmesh
|
||||
* \param e_kill: The edge to collapse
|
||||
* \param v_kill: The vertex to collapse into the edge
|
||||
* \param fac: The factor along the edge
|
||||
* \param join_faces: When true the faces around the vertex will be joined
|
||||
* otherwise collapse the vertex by merging the 2 edges this vert touches into one.
|
||||
* \param kill_degenerate_faces: Removes faces with less than 3 verts after collapsing.
|
||||
*
|
||||
* \returns The New Edge
|
||||
*/
|
||||
BMEdge *BM_vert_collapse_faces(BMesh *bm,
|
||||
BMEdge *e_kill,
|
||||
BMVert *v_kill,
|
||||
@@ -53,6 +153,13 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm,
|
||||
const bool join_faces,
|
||||
const bool kill_degenerate_faces,
|
||||
const bool kill_duplicate_faces);
|
||||
/**
|
||||
* \brief Vert Collapse Faces
|
||||
*
|
||||
* Collapses a vertex onto another vertex it shares an edge with.
|
||||
*
|
||||
* \return The New Edge
|
||||
*/
|
||||
BMEdge *BM_vert_collapse_edge(BMesh *bm,
|
||||
BMEdge *e_kill,
|
||||
BMVert *v_kill,
|
||||
@@ -60,24 +167,101 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm,
|
||||
const bool kill_degenerate_faces,
|
||||
const bool kill_duplicate_faces);
|
||||
|
||||
/**
|
||||
* Collapse and edge into a single vertex.
|
||||
*/
|
||||
BMVert *BM_edge_collapse(BMesh *bm,
|
||||
BMEdge *e_kill,
|
||||
BMVert *v_kill,
|
||||
const bool do_del,
|
||||
const bool kill_degenerate_faces);
|
||||
|
||||
/**
|
||||
* \brief Edge Split
|
||||
*
|
||||
* <pre>
|
||||
* Before: v
|
||||
* +-----------------------------------+
|
||||
* e
|
||||
*
|
||||
* After: v v_new (returned)
|
||||
* +-----------------+-----------------+
|
||||
* r_e e
|
||||
* </pre>
|
||||
*
|
||||
* \param e: The edge to split.
|
||||
* \param v: One of the vertices in \a e and defines the "from" end of the splitting operation,
|
||||
* the new vertex will be \a fac of the way from \a v to the other end.
|
||||
* \param r_e: The newly created edge.
|
||||
* \return The new vertex.
|
||||
*/
|
||||
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac);
|
||||
|
||||
/**
|
||||
* \brief Split an edge multiple times evenly
|
||||
*
|
||||
* \param r_varr: Optional array, verts in between (v1 -> v2)
|
||||
*/
|
||||
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr);
|
||||
|
||||
/**
|
||||
* Swap v1 & v2
|
||||
*
|
||||
* \note Typically we shouldn't care about this, however it's used when extruding wire edges.
|
||||
*/
|
||||
void BM_edge_verts_swap(BMEdge *e);
|
||||
|
||||
bool BM_face_validate(BMFace *face, FILE *err);
|
||||
|
||||
/**
|
||||
* Calculate the 2 loops which _would_ make up the newly rotated Edge
|
||||
* but don't actually change anything.
|
||||
*
|
||||
* Use this to further inspect if the loops to be connected have issues:
|
||||
*
|
||||
* Examples:
|
||||
* - the newly formed edge already exists
|
||||
* - the new face would be degenerate (zero area / concave / bow-tie)
|
||||
* - may want to measure if the new edge gives improved results topology.
|
||||
* over the old one, as with beauty fill.
|
||||
*
|
||||
* \note #BM_edge_rotate_check must have already run.
|
||||
*/
|
||||
void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2);
|
||||
/**
|
||||
* \brief Check if Rotate Edge is OK
|
||||
*
|
||||
* Quick check to see if we could rotate the edge,
|
||||
* use this to avoid calling exceptions on common cases.
|
||||
*/
|
||||
bool BM_edge_rotate_check(BMEdge *e);
|
||||
/**
|
||||
* \brief Check if Edge Rotate Gives Degenerate Faces
|
||||
*
|
||||
* Check 2 cases
|
||||
* 1) does the newly forms edge form a flipped face (compare with previous cross product)
|
||||
* 2) does the newly formed edge cause a zero area corner (or close enough to be almost zero)
|
||||
*
|
||||
* \param e: The edge to test rotation.
|
||||
* \param l1, l2: are the loops of the proposed verts to rotate too and should
|
||||
* be the result of calling #BM_edge_calc_rotate
|
||||
*/
|
||||
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2);
|
||||
bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2);
|
||||
/**
|
||||
* \brief Rotate Edge
|
||||
*
|
||||
* Spins an edge topologically,
|
||||
* either counter-clockwise or clockwise depending on \a ccw.
|
||||
*
|
||||
* \return The spun edge, NULL on error
|
||||
* (e.g., if the edge isn't surrounded by exactly two faces).
|
||||
*
|
||||
* \note This works by dissolving the edge then re-creating it,
|
||||
* so the returned edge won't have the same pointer address as the original one.
|
||||
*
|
||||
* \see header definition for \a check_flag enum.
|
||||
*/
|
||||
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag);
|
||||
|
||||
/** Flags for #BM_edge_rotate */
|
||||
@@ -92,6 +276,9 @@ enum {
|
||||
BM_EDGEROT_CHECK_BEAUTY = (1 << 3),
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Rip a single face from a vertex fan
|
||||
*/
|
||||
BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep);
|
||||
BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep);
|
||||
BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len);
|
||||
|
||||
@@ -341,50 +341,161 @@ typedef struct BMOpDefine {
|
||||
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. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name BMesh Operator API
|
||||
*
|
||||
* \note data types that use pointers (arrays, etc) must _never_ have it set directly.
|
||||
* Don't #BMO_slot_ptr_set to pass in a list of edges or any arrays.
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \brief BMESH OPSTACK INIT OP
|
||||
*
|
||||
* Initializes an operator structure to a certain type
|
||||
*/
|
||||
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. */
|
||||
/**
|
||||
* \brief BMESH OPSTACK EXEC OP
|
||||
*
|
||||
* Executes a passed in operator.
|
||||
*
|
||||
* This handles the allocation and freeing of temporary tool flag
|
||||
* layers and starting/stopping the modeling loop.
|
||||
* Can be called from other operators exec callbacks as well.
|
||||
*/
|
||||
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). */
|
||||
/**
|
||||
* \brief BMESH OPSTACK FINISH OP
|
||||
*
|
||||
* Does housekeeping chores related to finishing up an operator.
|
||||
*
|
||||
* \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. */
|
||||
/**
|
||||
* Count the number of elements with the specified flag enabled.
|
||||
* type can be a bit-mask 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. */
|
||||
/**
|
||||
* Count the number of elements with the specified flag disabled.
|
||||
* type can be a bit-mask 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-----------*/
|
||||
/**
|
||||
* \brief BMESH OPSTACK PUSH
|
||||
*
|
||||
* Pushes the opstack down one level and allocates a new flag layer if appropriate.
|
||||
*/
|
||||
void BMO_push(BMesh *bm, BMOperator *op);
|
||||
/**
|
||||
* \brief 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);
|
||||
|
||||
/* Executes an operator. */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Formatted Operator Initialization/Execution
|
||||
*
|
||||
* Format Strings for #BMOperator Initialization.
|
||||
*
|
||||
* This system is used to execute or initialize an operator,
|
||||
* using a formatted-string system.
|
||||
*
|
||||
* The basic format for the format string is:
|
||||
* `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* \code{.c}
|
||||
* BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
|
||||
* "delete context=%i geom=%hv",
|
||||
* DEL_ONLYFACES, BM_ELEM_SELECT);
|
||||
* \endcode
|
||||
* **Primitive Types**
|
||||
* - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
|
||||
* - `i` - int. #BMO_OP_SLOT_INT
|
||||
* - `f` - float. #BMO_OP_SLOT_FLT
|
||||
* - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
|
||||
* - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
|
||||
* - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
|
||||
* - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
|
||||
* **Utility**
|
||||
*
|
||||
* Pass an existing slot which is copied to either an input or output slot.
|
||||
* Taking the operator and slot-name pair of args (BMOperator *, const char *).
|
||||
* - `s` - slot_in (lower case)
|
||||
* - `S` - slot_out (upper case)
|
||||
* **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
|
||||
* - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
|
||||
* - `eb` - elem buffer, take an array and a length.
|
||||
* - `av` - all verts
|
||||
* - `ae` - all edges
|
||||
* - `af` - all faces
|
||||
* - `hv` - header flagged verts (hflag)
|
||||
* - `he` - header flagged edges (hflag)
|
||||
* - `hf` - header flagged faces (hflag)
|
||||
* - `Hv` - header flagged verts (hflag off)
|
||||
* - `He` - header flagged edges (hflag off)
|
||||
* - `Hf` - header flagged faces (hflag off)
|
||||
* - `fv` - flagged verts (oflag)
|
||||
* - `fe` - flagged edges (oflag)
|
||||
* - `ff` - flagged faces (oflag)
|
||||
* - `Fv` - flagged verts (oflag off)
|
||||
* - `Fe` - flagged edges (oflag off)
|
||||
* - `Ff` - flagged faces (oflag off)
|
||||
*
|
||||
* \note The common v/e/f suffix can be mixed,
|
||||
* so `avef` is can be used for all verts, edges and faces.
|
||||
* Order is not important so `Hfev` is also valid (all un-flagged verts, edges and faces).
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/** 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
|
||||
/**
|
||||
* 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. */
|
||||
* 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. */
|
||||
/**
|
||||
* A `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 */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name BMesh Operator Slot Access
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \brief BMESH OPSTACK HAS SLOT
|
||||
*
|
||||
* \return Success if the slot if found.
|
||||
*/
|
||||
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. */
|
||||
/**
|
||||
* \brief BMESH OPSTACK GET SLOT
|
||||
*
|
||||
* Returns a pointer to the slot of type 'slot_code'
|
||||
*/
|
||||
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
|
||||
@@ -393,12 +504,20 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
|
||||
_bmo_slot_copy( \
|
||||
(op_src)->slots_src, slot_name_src, (op_dst)->slots_dst, slot_name_dst, (op_dst)->arena)
|
||||
|
||||
/**
|
||||
* \brief BMESH OPSTACK COPY SLOT
|
||||
*
|
||||
* define used.
|
||||
* Copies data from one slot to another.
|
||||
*/
|
||||
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,
|
||||
@@ -433,6 +552,10 @@ typedef enum {
|
||||
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);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name BMesh Operator Slot Get/Set
|
||||
* \{ */
|
||||
|
||||
void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
const float f);
|
||||
@@ -441,13 +564,17 @@ void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
|
||||
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);
|
||||
/**
|
||||
* Return a copy of the element buffer.
|
||||
*/
|
||||
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.
|
||||
/**
|
||||
* 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. */
|
||||
* passing in, e.g. pointer to an edit-mesh 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],
|
||||
@@ -455,10 +582,12 @@ void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
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. */
|
||||
/**
|
||||
* Only supports square matrices.
|
||||
* size must be 3 or 4; this api is meant only for transformation matrices.
|
||||
*
|
||||
* \note the matrix is stored in 4x4 form, and it's safe to call whichever function you want.
|
||||
*/
|
||||
void BMO_slot_mat_set(BMOperator *op,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
@@ -471,6 +600,8 @@ 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,
|
||||
@@ -479,19 +610,25 @@ void BMO_mesh_selected_remap(BMesh *bm,
|
||||
BMOpSlot *slot_face_map,
|
||||
const bool check_select);
|
||||
|
||||
/* copies the values from another slot to the end of the output slot */
|
||||
/**
|
||||
* 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)
|
||||
/**
|
||||
* Copies the values from another slot to the end of the output slot.
|
||||
*/
|
||||
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. */
|
||||
/**
|
||||
* Puts every element of type 'type' (which is a bit-mask) 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],
|
||||
@@ -499,8 +636,9 @@ void BMO_slot_buffer_from_enabled_flag(BMesh *bm,
|
||||
const char htype,
|
||||
const short oflag);
|
||||
|
||||
/* puts every element of type 'type' (which is a bitmask) without tool
|
||||
* flag 'flag', into a slot. */
|
||||
/**
|
||||
* Puts every element of type 'type' (which is a bit-mask) 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],
|
||||
@@ -508,27 +646,45 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
|
||||
const char htype,
|
||||
const short oflag);
|
||||
|
||||
/* tool-flags all elements inside an element slot array with flag flag. */
|
||||
/**
|
||||
* \brief BMO_FLAG_BUFFER
|
||||
*
|
||||
* Flags elements in a slots buffer
|
||||
*/
|
||||
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. */
|
||||
/**
|
||||
* \brief BMO_FLAG_BUFFER
|
||||
*
|
||||
* Removes flags from elements in a slots buffer
|
||||
*/
|
||||
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. */
|
||||
/**
|
||||
* \brief 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,
|
||||
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. */
|
||||
/**
|
||||
* \brief 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,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
@@ -536,19 +692,20 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm,
|
||||
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). */
|
||||
/**
|
||||
* Puts every element of type 'type' (which is a bit-mask) 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). */
|
||||
/**
|
||||
* Puts every element of type 'type' (which is a bit-mask) 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],
|
||||
@@ -564,14 +721,21 @@ void BMO_slot_buffer_from_array(BMOperator *op,
|
||||
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. */
|
||||
/** Return the number of elements inside a slot array. */
|
||||
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
|
||||
/** Return the number of elements inside a slot map. */
|
||||
int BMO_slot_map_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
|
||||
|
||||
/**
|
||||
* Inserts a key/value mapping into a mapping slot. note that it copies the
|
||||
* value, it doesn't store a reference to it.
|
||||
*/
|
||||
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. */
|
||||
/**
|
||||
* 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,
|
||||
@@ -583,6 +747,11 @@ void *BMO_slot_buffer_alloc(BMOperator *op,
|
||||
const char *slot_name,
|
||||
const int len);
|
||||
|
||||
/**
|
||||
* \brief BMO_ALL_TO_SLOT
|
||||
*
|
||||
* Copies all elements of a certain type into an operator slot.
|
||||
*/
|
||||
void BMO_slot_buffer_from_all(BMesh *bm,
|
||||
BMOperator *op,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
@@ -636,12 +805,22 @@ typedef struct BMOIter {
|
||||
|
||||
void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
|
||||
|
||||
/**
|
||||
* \brief New Iterator
|
||||
*
|
||||
* \param 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_iter_new(BMOIter *iter,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
const char restrictmask);
|
||||
void *BMO_iter_step(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_iter_map_value_p(BMOIter *iter);
|
||||
void *BMO_iter_map_value_ptr(BMOIter *iter);
|
||||
|
||||
@@ -660,6 +839,7 @@ bool BMO_iter_map_value_bool(BMOIter *iter);
|
||||
ele; \
|
||||
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter), i_++)
|
||||
|
||||
/* operator slot type information - size of one element of the type given. */
|
||||
extern const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES];
|
||||
|
||||
int BMO_opcode_from_opname(const char *opname);
|
||||
|
||||
@@ -42,7 +42,6 @@ static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
|
||||
static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *identifier);
|
||||
|
||||
/* operator slot type information - size of one element of the type given. */
|
||||
const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = {
|
||||
0, /* 0: BMO_OP_SLOT_SENTINEL */
|
||||
sizeof(int), /* 1: BMO_OP_SLOT_BOOL */
|
||||
@@ -70,11 +69,6 @@ void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
|
||||
op->flag &= ~op_flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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->toolflag_index++;
|
||||
@@ -90,13 +84,6 @@ void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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->toolflag_index > 0) {
|
||||
@@ -152,11 +139,6 @@ static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH OPSTACK INIT OP
|
||||
*
|
||||
* Initializes an operator structure to a certain type
|
||||
*/
|
||||
void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
|
||||
{
|
||||
int opcode = BMO_opcode_from_opname(opname);
|
||||
@@ -188,15 +170,6 @@ void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
|
||||
BLI_memarena_use_calloc(op->arena);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH OPSTACK EXEC OP
|
||||
*
|
||||
* Executes a passed in operator.
|
||||
*
|
||||
* This handles the allocation and freeing of temporary flag
|
||||
* layers and starting/stopping the modeling loop.
|
||||
* Can be called from other operators exec callbacks as well.
|
||||
*/
|
||||
void BMO_op_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
/* allocate tool flags on demand */
|
||||
@@ -216,11 +189,6 @@ void BMO_op_exec(BMesh *bm, BMOperator *op)
|
||||
BMO_pop(bm);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH OPSTACK FINISH OP
|
||||
*
|
||||
* Does housekeeping chores related to finishing up an operator.
|
||||
*/
|
||||
void BMO_op_finish(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_in, op->slots_in);
|
||||
@@ -238,22 +206,12 @@ void BMO_op_finish(BMesh *bm, BMOperator *op)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH OPSTACK HAS SLOT
|
||||
*
|
||||
* \return Success if the slot if found.
|
||||
*/
|
||||
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
|
||||
{
|
||||
int slot_code = bmo_name_to_slotcode(slot_args, identifier);
|
||||
return (slot_code >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH OPSTACK GET SLOT
|
||||
*
|
||||
* Returns a pointer to the slot of type 'slot_code'
|
||||
*/
|
||||
BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
|
||||
{
|
||||
int slot_code = bmo_name_to_slotcode_check(slot_args, identifier);
|
||||
@@ -267,12 +225,6 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
|
||||
return &slot_args[slot_code];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH OPSTACK COPY SLOT
|
||||
*
|
||||
* define used.
|
||||
* Copies data from one slot to another.
|
||||
*/
|
||||
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],
|
||||
@@ -393,7 +345,6 @@ void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
|
||||
slot->data.i = i;
|
||||
}
|
||||
|
||||
/* only supports square mats */
|
||||
void BMO_slot_mat_set(BMOperator *op,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
@@ -515,7 +466,6 @@ bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
|
||||
return slot->data.i;
|
||||
}
|
||||
|
||||
/* if you want a copy of the elem buffer */
|
||||
void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len)
|
||||
{
|
||||
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
|
||||
@@ -698,9 +648,6 @@ int BMO_slot_map_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name
|
||||
return BLI_ghash_len(slot->data.ghash);
|
||||
}
|
||||
|
||||
/* inserts a key/value mapping into a mapping slot. note that it copies the
|
||||
* value, it doesn't store a reference to it. */
|
||||
|
||||
void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, const void *data)
|
||||
{
|
||||
(void)op; /* Ignored in release builds. */
|
||||
@@ -796,11 +743,6 @@ void *BMO_slot_buffer_alloc(BMOperator *op,
|
||||
return slot->data.buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMO_ALL_TO_SLOT
|
||||
*
|
||||
* Copies all elements of a certain type into an operator slot.
|
||||
*/
|
||||
void BMO_slot_buffer_from_all(BMesh *bm,
|
||||
BMOperator *op,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
@@ -987,9 +929,6 @@ void *BMO_slot_buffer_get_single(BMOpSlot *slot)
|
||||
return slot->len ? (BMHeader *)slot->data.buf[0] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the values from another slot to the end of the output slot.
|
||||
*/
|
||||
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],
|
||||
@@ -1115,12 +1054,6 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
|
||||
bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
@@ -1155,12 +1088,6 @@ void BMO_slot_buffer_hflag_enable(BMesh *bm,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
@@ -1194,11 +1121,6 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMO_FLAG_BUFFER
|
||||
*
|
||||
* Flags elements in a slots buffer
|
||||
*/
|
||||
void BMO_slot_buffer_flag_enable(BMesh *bm,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
@@ -1221,11 +1143,6 @@ void BMO_slot_buffer_flag_enable(BMesh *bm,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMO_FLAG_BUFFER
|
||||
*
|
||||
* Removes flags from elements in a slots buffer
|
||||
*/
|
||||
void BMO_slot_buffer_flag_disable(BMesh *bm,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
@@ -1434,12 +1351,6 @@ void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
|
||||
return slot->data.buf ? *slot->data.buf : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief New Iterator
|
||||
*
|
||||
* \param 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_iter_new(BMOIter *iter,
|
||||
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
const char *slot_name,
|
||||
@@ -1513,10 +1424,6 @@ void *BMO_iter_step(BMOIter *iter)
|
||||
|
||||
/* used for iterating over mappings */
|
||||
|
||||
/**
|
||||
* 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_iter_map_value_p(BMOIter *iter)
|
||||
{
|
||||
return iter->val;
|
||||
@@ -1584,7 +1491,6 @@ bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* returns error code or 0 if no error */
|
||||
bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level)
|
||||
{
|
||||
BMOpError *err = bm->errorstack.first;
|
||||
@@ -1694,60 +1600,6 @@ static int BMO_opcode_from_opname_check(const char *opname)
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Format Strings for #BMOperator Initialization.
|
||||
*
|
||||
* This system is used to execute or initialize an operator,
|
||||
* using a formatted-string system.
|
||||
*
|
||||
* The basic format for the format string is:
|
||||
* `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* \code{.c}
|
||||
* BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
|
||||
* "delete context=%i geom=%hv",
|
||||
* DEL_ONLYFACES, BM_ELEM_SELECT);
|
||||
* \endcode
|
||||
* **Primitive Types**
|
||||
* - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
|
||||
* - `i` - int. #BMO_OP_SLOT_INT
|
||||
* - `f` - float. #BMO_OP_SLOT_FLT
|
||||
* - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
|
||||
* - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
|
||||
* - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
|
||||
* - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
|
||||
* **Utility**
|
||||
*
|
||||
* Pass an existing slot which is copied to either an input or output slot.
|
||||
* Taking the operator and slot-name pair of args (BMOperator *, const char *).
|
||||
* - `s` - slot_in (lower case)
|
||||
* - `S` - slot_out (upper case)
|
||||
* **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
|
||||
* - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
|
||||
* - `eb` - elem buffer, take an array and a length.
|
||||
* - `av` - all verts
|
||||
* - `ae` - all edges
|
||||
* - `af` - all faces
|
||||
* - `hv` - header flagged verts (hflag)
|
||||
* - `he` - header flagged edges (hflag)
|
||||
* - `hf` - header flagged faces (hflag)
|
||||
* - `Hv` - header flagged verts (hflag off)
|
||||
* - `He` - header flagged edges (hflag off)
|
||||
* - `Hf` - header flagged faces (hflag off)
|
||||
* - `fv` - flagged verts (oflag)
|
||||
* - `fe` - flagged edges (oflag)
|
||||
* - `ff` - flagged faces (oflag)
|
||||
* - `Fv` - flagged verts (oflag off)
|
||||
* - `Fe` - flagged edges (oflag off)
|
||||
* - `Ff` - flagged faces (oflag off)
|
||||
*
|
||||
* \note The common v/e/f suffix can be mixed,
|
||||
* so `avef` is can be used for all verts, edges and faces.
|
||||
* Order is not important so `Hfev` is also valid (all un-flagged verts, edges and faces).
|
||||
*/
|
||||
|
||||
bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, va_list vlist)
|
||||
{
|
||||
// BMOpDefine *def;
|
||||
|
||||
@@ -170,17 +170,50 @@ void BM_mesh_esubdivide(BMesh *bm,
|
||||
const short use_only_quads,
|
||||
const int seed);
|
||||
|
||||
/**
|
||||
* Fills first available UV-map with grid-like UV's for all faces with `oflag` set.
|
||||
*
|
||||
* \param bm: The BMesh to operate on
|
||||
* \param x_segments: The x-resolution of the grid
|
||||
* \param y_segments: The y-resolution of the grid
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_grid(BMesh *bm,
|
||||
const uint x_segments,
|
||||
const uint y_segments,
|
||||
const short oflag,
|
||||
const int cd_loop_uv_offset);
|
||||
/**
|
||||
* Fills first available UV-map with spherical projected UVs for all faces with `oflag` set.
|
||||
*
|
||||
* \param bm: The BMesh to operate on
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_offset);
|
||||
/**
|
||||
* Fills first available UV-map with 2D projected UVs for all faces with `oflag` set.
|
||||
*
|
||||
* \param bm: The BMesh to operate on.
|
||||
* \param mat: The transform matrix applied to the created circle.
|
||||
* \param radius: The size of the circle.
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_circle(BMesh *bm,
|
||||
float mat[4][4],
|
||||
const float radius,
|
||||
const short oflag,
|
||||
const int cd_loop_uv_offset);
|
||||
/**
|
||||
* Fills first available UV-map with cylinder/cone-like UVs for all faces with `oflag` set.
|
||||
*
|
||||
* \param bm: The BMesh to operate on.
|
||||
* \param mat: The transform matrix applied to the created cone/cylinder.
|
||||
* \param radius_top: The size of the top end of the cone/cylinder.
|
||||
* \param radius_bottom: The size of the bottom end of the cone/cylinder.
|
||||
* \param segments: The number of subdivisions in the sides of the cone/cylinder.
|
||||
* \param cap_ends: Whether the ends of the cone/cylinder are filled or not.
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_cone(BMesh *bm,
|
||||
float mat[4][4],
|
||||
const float radius_top,
|
||||
@@ -189,6 +222,15 @@ void BM_mesh_calc_uvs_cone(BMesh *bm,
|
||||
const bool cap_ends,
|
||||
const short oflag,
|
||||
const int cd_loop_uv_offset);
|
||||
/**
|
||||
* Fills first available UV-map with cube-like UVs for all faces with `oflag` set.
|
||||
*
|
||||
* \note Expects tagged faces to be six quads.
|
||||
* \note Caller must order faces for correct alignment.
|
||||
*
|
||||
* \param bm: The BMesh to operate on.
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag);
|
||||
|
||||
#include "intern/bmesh_operator_api_inline.h"
|
||||
|
||||
@@ -117,15 +117,6 @@ static void bm_face_calc_poly_center_median_vertex_cos(const BMFace *f,
|
||||
mul_v3_fl(r_cent, 1.0f / f->len);
|
||||
}
|
||||
|
||||
/**
|
||||
* For tools that insist on using triangles, ideally we would cache this data.
|
||||
*
|
||||
* \param use_fixed_quad: When true,
|
||||
* always split quad along (0 -> 2) regardless of concave corners,
|
||||
* (as done in #BM_mesh_calc_tessellation).
|
||||
* \param r_loops: Store face loop pointers, (f->len)
|
||||
* \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
|
||||
*/
|
||||
void BM_face_calc_tessellation(const BMFace *f,
|
||||
const bool use_fixed_quad,
|
||||
BMLoop **r_loops,
|
||||
@@ -177,9 +168,6 @@ void BM_face_calc_tessellation(const BMFace *f,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a point inside the face.
|
||||
*/
|
||||
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
|
||||
{
|
||||
const BMLoop *l_tri[3];
|
||||
@@ -218,9 +206,6 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
|
||||
mid_v3_v3v3v3(r_co, l_tri[0]->v->co, l_tri[1]->v->co, l_tri[2]->v->co);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the area of the face
|
||||
*/
|
||||
float BM_face_calc_area(const BMFace *f)
|
||||
{
|
||||
/* inline 'area_poly_v3' logic, avoid creating a temp array */
|
||||
@@ -235,9 +220,6 @@ float BM_face_calc_area(const BMFace *f)
|
||||
return len_v3(n) * 0.5f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the area of the face in world space.
|
||||
*/
|
||||
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
|
||||
{
|
||||
/* inline 'area_poly_v3' logic, avoid creating a temp array */
|
||||
@@ -257,9 +239,6 @@ float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
|
||||
return len_v3(n) * 0.5f;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the area of UV face
|
||||
*/
|
||||
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
|
||||
{
|
||||
/* inline 'area_poly_v2' logic, avoid creating a temp array */
|
||||
@@ -276,9 +255,6 @@ float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
|
||||
return fabsf(cross * 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* compute the perimeter of an ngon
|
||||
*/
|
||||
float BM_face_calc_perimeter(const BMFace *f)
|
||||
{
|
||||
const BMLoop *l_iter, *l_first;
|
||||
@@ -292,9 +268,6 @@ float BM_face_calc_perimeter(const BMFace *f)
|
||||
return perimeter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the perimeter of a ngon in world space.
|
||||
*/
|
||||
float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3])
|
||||
{
|
||||
const BMLoop *l_iter, *l_first;
|
||||
@@ -355,14 +328,6 @@ static int bm_vert_tri_find_unique_edge(BMVert *verts[3])
|
||||
return order[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a tangent from any 3 vertices.
|
||||
*
|
||||
* The tangent aligns to the most *unique* edge
|
||||
* (the edge most unlike the other two).
|
||||
*
|
||||
* \param r_tangent: Calculated unit length tangent (return value).
|
||||
*/
|
||||
void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
|
||||
{
|
||||
const int index = bm_vert_tri_find_unique_edge(verts);
|
||||
@@ -372,14 +337,6 @@ void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
|
||||
normalize_v3(r_tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a tangent from any 3 vertices,
|
||||
*
|
||||
* The tangent follows the center-line formed by the most unique edges center
|
||||
* and the opposite vertex.
|
||||
*
|
||||
* \param r_tangent: Calculated unit length tangent (return value).
|
||||
*/
|
||||
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
|
||||
{
|
||||
const int index = bm_vert_tri_find_unique_edge(verts);
|
||||
@@ -394,9 +351,6 @@ void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
|
||||
normalize_v3(r_tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the tangent of the face, using the longest edge.
|
||||
*/
|
||||
void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
|
||||
{
|
||||
const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
|
||||
@@ -406,11 +360,6 @@ void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
|
||||
normalize_v3(r_tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the tangent of the face, using the two longest disconnected edges.
|
||||
*
|
||||
* \param r_tangent: Calculated unit length tangent (return value).
|
||||
*/
|
||||
void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
|
||||
{
|
||||
if (f->len == 3) {
|
||||
@@ -471,11 +420,6 @@ void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the tangent of the face, using the edge farthest away from any vertex in the face.
|
||||
*
|
||||
* \param r_tangent: Calculated unit length tangent (return value).
|
||||
*/
|
||||
void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
|
||||
{
|
||||
BMLoop *l_iter, *l_first;
|
||||
@@ -508,11 +452,6 @@ void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
|
||||
normalize_v3(r_tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the tangent of the face, using longest distance between vertices on the face.
|
||||
*
|
||||
* \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
|
||||
*/
|
||||
void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
|
||||
{
|
||||
BMLoop *l_iter, *l_first;
|
||||
@@ -541,11 +480,6 @@ void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
|
||||
normalize_v3(r_tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a meaningful direction along the face (use for gizmo axis).
|
||||
*
|
||||
* \note Callers shouldn't depend on the *exact* method used here.
|
||||
*/
|
||||
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
|
||||
{
|
||||
if (f->len == 3) {
|
||||
@@ -564,9 +498,6 @@ void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* expands bounds (min/max must be initialized).
|
||||
*/
|
||||
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
|
||||
{
|
||||
const BMLoop *l_iter, *l_first;
|
||||
@@ -576,9 +507,6 @@ void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
||||
/**
|
||||
* computes center of face in 3d. uses center of bounding box.
|
||||
*/
|
||||
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
|
||||
{
|
||||
const BMLoop *l_iter, *l_first;
|
||||
@@ -594,9 +522,6 @@ void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
|
||||
mid_v3_v3v3(r_cent, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* computes center of face in 3d. uses center of bounding box.
|
||||
*/
|
||||
void BM_face_calc_center_bounds_vcos(const BMesh *bm,
|
||||
const BMFace *f,
|
||||
float r_cent[3],
|
||||
@@ -619,9 +544,6 @@ void BM_face_calc_center_bounds_vcos(const BMesh *bm,
|
||||
mid_v3_v3v3(r_cent, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* computes the center of a face, using the mean average
|
||||
*/
|
||||
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
|
||||
{
|
||||
const BMLoop *l_iter, *l_first;
|
||||
@@ -635,10 +557,6 @@ void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
|
||||
mul_v3_fl(r_cent, 1.0f / (float)f->len);
|
||||
}
|
||||
|
||||
/**
|
||||
* computes the center of a face, using the mean average
|
||||
* weighted by edge length
|
||||
*/
|
||||
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
|
||||
{
|
||||
const BMLoop *l_iter;
|
||||
@@ -663,12 +581,6 @@ void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief POLY ROTATE PLANE
|
||||
*
|
||||
* Rotates a polygon so that its
|
||||
* normal is pointing towards the mesh Z axis
|
||||
*/
|
||||
void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts)
|
||||
{
|
||||
float mat[3][3];
|
||||
@@ -684,9 +596,6 @@ void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nver
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* updates face and vertex normals incident on an edge
|
||||
*/
|
||||
void BM_edge_normals_update(BMEdge *e)
|
||||
{
|
||||
BMIter iter;
|
||||
@@ -800,24 +709,11 @@ void BM_vert_normal_update_all(BMVert *v)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update a vert normal (but not the faces incident on it)
|
||||
*/
|
||||
void BM_vert_normal_update(BMVert *v)
|
||||
{
|
||||
BM_vert_calc_normal(v, v->no);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH UPDATE FACE NORMAL
|
||||
*
|
||||
* Updates the stored normal for the
|
||||
* given face. Requires that a buffer
|
||||
* of sufficient length to store projected
|
||||
* coordinates for all of the face's vertices
|
||||
* is passed in as well.
|
||||
*/
|
||||
|
||||
float BM_face_calc_normal(const BMFace *f, float r_no[3])
|
||||
{
|
||||
BMLoop *l;
|
||||
@@ -849,7 +745,6 @@ void BM_face_normal_update(BMFace *f)
|
||||
BM_face_calc_normal(f, f->no);
|
||||
}
|
||||
|
||||
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
|
||||
float BM_face_calc_normal_vcos(const BMesh *bm,
|
||||
const BMFace *f,
|
||||
float r_no[3],
|
||||
@@ -884,12 +779,6 @@ float BM_face_calc_normal_vcos(const BMesh *bm,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a normal from a vertex cloud.
|
||||
*
|
||||
* \note We could make a higher quality version that takes all vertices into account.
|
||||
* Currently it finds 4 outer most points returning its normal.
|
||||
*/
|
||||
void BM_verts_calc_normal_from_cloud_ex(
|
||||
BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent)
|
||||
{
|
||||
@@ -991,9 +880,6 @@ void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal
|
||||
BM_verts_calc_normal_from_cloud_ex(varr, varr_len, r_normal, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the face subset normal.
|
||||
*/
|
||||
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
|
||||
{
|
||||
const float *v_prev, *v_curr;
|
||||
@@ -1014,7 +900,6 @@ float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, fl
|
||||
return normalize_v3(r_no);
|
||||
}
|
||||
|
||||
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
|
||||
void BM_face_calc_center_median_vcos(const BMesh *bm,
|
||||
const BMFace *f,
|
||||
float r_cent[3],
|
||||
@@ -1027,12 +912,6 @@ void BM_face_calc_center_median_vcos(const BMesh *bm,
|
||||
bm_face_calc_poly_center_median_vertex_cos(f, r_cent, vertexCos);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Face Flip Normal
|
||||
*
|
||||
* Reverses the winding of a face.
|
||||
* \note This updates the calculated normal.
|
||||
*/
|
||||
void BM_face_normal_flip_ex(BMesh *bm,
|
||||
BMFace *f,
|
||||
const int cd_loop_mdisp_offset,
|
||||
@@ -1048,16 +927,6 @@ void BM_face_normal_flip(BMesh *bm, BMFace *f)
|
||||
BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* BM POINT IN FACE
|
||||
*
|
||||
* Projects co onto face f, and returns true if it is inside
|
||||
* the face bounds.
|
||||
*
|
||||
* \note this uses a best-axis projection test,
|
||||
* instead of projecting co directly into f's orientation space,
|
||||
* so there might be accuracy issues.
|
||||
*/
|
||||
bool BM_face_point_inside_test(const BMFace *f, const float co[3])
|
||||
{
|
||||
float axis_mat[3][3];
|
||||
@@ -1080,29 +949,6 @@ bool BM_face_point_inside_test(const BMFace *f, const float co[3])
|
||||
return isect_point_poly_v2(co_2d, projverts, f->len, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH TRIANGULATE FACE
|
||||
*
|
||||
* Breaks all quads and ngons down to triangles.
|
||||
* It uses polyfill for the ngons splitting, and
|
||||
* the beautify operator when use_beauty is true.
|
||||
*
|
||||
* \param r_faces_new: if non-null, must be an array of BMFace pointers,
|
||||
* with a length equal to (f->len - 3). It will be filled with the new
|
||||
* triangles (not including the original triangle).
|
||||
*
|
||||
* \param r_faces_double: When newly created faces are duplicates of existing faces,
|
||||
* they're added to this list. Caller must handle de-duplication.
|
||||
* This is done because its possible _all_ faces exist already,
|
||||
* and in that case we would have to remove all faces including the one passed,
|
||||
* which causes complications adding/removing faces while looking over them.
|
||||
*
|
||||
* \note The number of faces is _almost_ always (f->len - 3),
|
||||
* However there may be faces that already occupying the
|
||||
* triangles we would make, so the caller must check \a r_faces_new_tot.
|
||||
*
|
||||
* \note use_tag tags new flags and edges.
|
||||
*/
|
||||
void BM_face_triangulate(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMFace **r_faces_new,
|
||||
@@ -1325,14 +1171,6 @@ void BM_face_triangulate(BMesh *bm,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* each pair of loops defines a new edge, a split. this function goes
|
||||
* through and sets pairs that are geometrically invalid to null. a
|
||||
* split is invalid, if it forms a concave angle or it intersects other
|
||||
* edges in the face, or it intersects another split. in the case of
|
||||
* intersecting splits, only the first of the set of intersecting
|
||||
* splits survives
|
||||
*/
|
||||
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
|
||||
{
|
||||
float out[2] = {-FLT_MAX, -FLT_MAX};
|
||||
@@ -1430,10 +1268,6 @@ void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int l
|
||||
#undef EDGE_SHARE_VERT
|
||||
}
|
||||
|
||||
/**
|
||||
* This simply checks that the verts don't connect faces which would have more optimal splits.
|
||||
* but _not_ check for correctness.
|
||||
*/
|
||||
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
|
||||
{
|
||||
int i;
|
||||
@@ -1447,12 +1281,6 @@ void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Small utility functions for fast access
|
||||
*
|
||||
* faster alternative to:
|
||||
* BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
|
||||
*/
|
||||
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
|
||||
{
|
||||
BMLoop *l = BM_FACE_FIRST_LOOP(f);
|
||||
@@ -1466,10 +1294,6 @@ void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
|
||||
r_verts[2] = l->v;
|
||||
}
|
||||
|
||||
/**
|
||||
* faster alternative to:
|
||||
* BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 4);
|
||||
*/
|
||||
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
|
||||
{
|
||||
BMLoop *l = BM_FACE_FIRST_LOOP(f);
|
||||
@@ -1485,12 +1309,6 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
|
||||
r_verts[3] = l->v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Small utility functions for fast access
|
||||
*
|
||||
* faster alternative to:
|
||||
* BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
|
||||
*/
|
||||
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
|
||||
{
|
||||
BMLoop *l = BM_FACE_FIRST_LOOP(f);
|
||||
@@ -1504,10 +1322,6 @@ void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
|
||||
r_loops[2] = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* faster alternative to:
|
||||
* BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4);
|
||||
*/
|
||||
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4])
|
||||
{
|
||||
BMLoop *l = BM_FACE_FIRST_LOOP(f);
|
||||
|
||||
@@ -25,68 +25,200 @@ struct Heap;
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
|
||||
/**
|
||||
* For tools that insist on using triangles, ideally we would cache this data.
|
||||
*
|
||||
* \param use_fixed_quad: When true,
|
||||
* always split quad along (0 -> 2) regardless of concave corners,
|
||||
* (as done in #BM_mesh_calc_tessellation).
|
||||
* \param r_loops: Store face loop pointers, (f->len)
|
||||
* \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
|
||||
*/
|
||||
void BM_face_calc_tessellation(const BMFace *f,
|
||||
const bool use_fixed_quad,
|
||||
BMLoop **r_loops,
|
||||
uint (*r_index)[3]);
|
||||
/**
|
||||
* Return a point inside the face.
|
||||
*/
|
||||
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]);
|
||||
|
||||
/**
|
||||
* \brief BMESH UPDATE FACE NORMAL
|
||||
*
|
||||
* Updates the stored normal for the
|
||||
* given face. Requires that a buffer
|
||||
* of sufficient length to store projected
|
||||
* coordinates for all of the face's vertices
|
||||
* is passed in as well.
|
||||
*/
|
||||
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
|
||||
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
|
||||
float BM_face_calc_normal_vcos(const BMesh *bm,
|
||||
const BMFace *f,
|
||||
float r_no[3],
|
||||
float const (*vertexCos)[3]) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Calculate a normal from a vertex cloud.
|
||||
*
|
||||
* \note We could make a higher quality version that takes all vertices into account.
|
||||
* Currently it finds 4 outer most points returning its normal.
|
||||
*/
|
||||
void BM_verts_calc_normal_from_cloud_ex(
|
||||
BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent);
|
||||
void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal[3]);
|
||||
|
||||
/**
|
||||
* Calculates the face subset normal.
|
||||
*/
|
||||
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* get the area of the face
|
||||
*/
|
||||
float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Get the area of the face in world space.
|
||||
*/
|
||||
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* get the area of UV face
|
||||
*/
|
||||
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* compute the perimeter of an ngon
|
||||
*/
|
||||
float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Calculate the perimeter of a ngon in world space.
|
||||
*/
|
||||
float BM_face_calc_perimeter_with_mat3(const BMFace *f,
|
||||
const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Compute the tangent of the face, using the longest edge.
|
||||
*/
|
||||
void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* Compute the tangent of the face, using the two longest disconnected edges.
|
||||
*
|
||||
* \param r_tangent: Calculated unit length tangent (return value).
|
||||
*/
|
||||
void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* Compute the tangent of the face, using the edge farthest away from any vertex in the face.
|
||||
*
|
||||
* \param r_tangent: Calculated unit length tangent (return value).
|
||||
*/
|
||||
void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* Compute the tangent of the face, using longest distance between vertices on the face.
|
||||
*
|
||||
* \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
|
||||
*/
|
||||
void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* Compute a meaningful direction along the face (use for gizmo axis).
|
||||
*
|
||||
* \note Callers shouldn't depend on the *exact* method used here.
|
||||
*/
|
||||
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* computes center of face in 3d. uses center of bounding box.
|
||||
*/
|
||||
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* computes center of face in 3d. uses center of bounding box.
|
||||
*/
|
||||
void BM_face_calc_center_bounds_vcos(const BMesh *bm,
|
||||
const BMFace *f,
|
||||
float r_center[3],
|
||||
float const (*vertexCos)[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* computes the center of a face, using the mean average
|
||||
*/
|
||||
void BM_face_calc_center_median(const BMFace *f, float r_center[3]) ATTR_NONNULL();
|
||||
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
|
||||
void BM_face_calc_center_median_vcos(const BMesh *bm,
|
||||
const BMFace *f,
|
||||
float r_center[3],
|
||||
float const (*vertexCos)[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* computes the center of a face, using the mean average
|
||||
* weighted by edge length
|
||||
*/
|
||||
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3]) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* expands bounds (min/max must be initialized).
|
||||
*/
|
||||
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3]);
|
||||
|
||||
void BM_face_normal_update(BMFace *f) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* updates face and vertex normals incident on an edge
|
||||
*/
|
||||
void BM_edge_normals_update(BMEdge *e) ATTR_NONNULL();
|
||||
|
||||
bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3]);
|
||||
bool BM_vert_calc_normal(const BMVert *v, float r_no[3]);
|
||||
/**
|
||||
* update a vert normal (but not the faces incident on it)
|
||||
*/
|
||||
void BM_vert_normal_update(BMVert *v) ATTR_NONNULL();
|
||||
void BM_vert_normal_update_all(BMVert *v) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* \brief Face Flip Normal
|
||||
*
|
||||
* Reverses the winding of a face.
|
||||
* \note This updates the calculated normal.
|
||||
*/
|
||||
void BM_face_normal_flip_ex(BMesh *bm,
|
||||
BMFace *f,
|
||||
const int cd_loop_mdisp_offset,
|
||||
const bool use_loop_mdisp_flip) ATTR_NONNULL();
|
||||
void BM_face_normal_flip(BMesh *bm, BMFace *f) ATTR_NONNULL();
|
||||
/**
|
||||
* BM POINT IN FACE
|
||||
*
|
||||
* Projects co onto face f, and returns true if it is inside
|
||||
* the face bounds.
|
||||
*
|
||||
* \note this uses a best-axis projection test,
|
||||
* instead of projecting co directly into f's orientation space,
|
||||
* so there might be accuracy issues.
|
||||
*/
|
||||
bool BM_face_point_inside_test(const BMFace *f, const float co[3]) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* \brief BMESH TRIANGULATE FACE
|
||||
*
|
||||
* Breaks all quads and ngons down to triangles.
|
||||
* It uses polyfill for the ngons splitting, and
|
||||
* the beautify operator when use_beauty is true.
|
||||
*
|
||||
* \param r_faces_new: if non-null, must be an array of BMFace pointers,
|
||||
* with a length equal to (f->len - 3). It will be filled with the new
|
||||
* triangles (not including the original triangle).
|
||||
*
|
||||
* \param r_faces_double: When newly created faces are duplicates of existing faces,
|
||||
* they're added to this list. Caller must handle de-duplication.
|
||||
* This is done because its possible _all_ faces exist already,
|
||||
* and in that case we would have to remove all faces including the one passed,
|
||||
* which causes complications adding/removing faces while looking over them.
|
||||
*
|
||||
* \note The number of faces is _almost_ always (f->len - 3),
|
||||
* However there may be faces that already occupying the
|
||||
* triangles we would make, so the caller must check \a r_faces_new_tot.
|
||||
*
|
||||
* \note use_tag tags new flags and edges.
|
||||
*/
|
||||
void BM_face_triangulate(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMFace **r_faces_new,
|
||||
@@ -100,14 +232,62 @@ void BM_face_triangulate(BMesh *bm,
|
||||
struct MemArena *pf_arena,
|
||||
struct Heap *pf_heap) ATTR_NONNULL(1, 2);
|
||||
|
||||
/**
|
||||
* each pair of loops defines a new edge, a split. this function goes
|
||||
* through and sets pairs that are geometrically invalid to null. a
|
||||
* split is invalid, if it forms a concave angle or it intersects other
|
||||
* edges in the face, or it intersects another split. in the case of
|
||||
* intersecting splits, only the first of the set of intersecting
|
||||
* splits survives
|
||||
*/
|
||||
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
|
||||
/**
|
||||
* This simply checks that the verts don't connect faces which would have more optimal splits.
|
||||
* but _not_ check for correctness.
|
||||
*/
|
||||
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Small utility functions for fast access
|
||||
*
|
||||
* faster alternative to:
|
||||
* BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
|
||||
*/
|
||||
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* faster alternative to:
|
||||
* BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 4);
|
||||
*/
|
||||
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Small utility functions for fast access
|
||||
*
|
||||
* faster alternative to:
|
||||
* BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
|
||||
*/
|
||||
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* faster alternative to:
|
||||
* BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4);
|
||||
*/
|
||||
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Calculate a tangent from any 3 vertices.
|
||||
*
|
||||
* The tangent aligns to the most *unique* edge
|
||||
* (the edge most unlike the other two).
|
||||
*
|
||||
* \param r_tangent: Calculated unit length tangent (return value).
|
||||
*/
|
||||
void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]);
|
||||
/**
|
||||
* Calculate a tangent from any 3 vertices,
|
||||
*
|
||||
* The tangent follows the center-line formed by the most unique edges center
|
||||
* and the opposite vertex.
|
||||
*
|
||||
* \param r_tangent: Calculated unit length tangent (return value).
|
||||
*/
|
||||
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]);
|
||||
|
||||
@@ -452,14 +452,6 @@ static bool bm_face_split_edgenet_find_loop(BMVert *v_init,
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a face into many smaller faces defined by an edge-net.
|
||||
* handle customdata and degenerate cases.
|
||||
*
|
||||
* - Isolated holes or unsupported face configurations, will be ignored.
|
||||
* - Customdata calculations aren't efficient
|
||||
* (need to calculate weights for each vert).
|
||||
*/
|
||||
bool BM_face_split_edgenet(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMEdge **edge_net,
|
||||
@@ -1223,14 +1215,6 @@ static bool bm_vert_partial_connect_check_overlap(const int *remap,
|
||||
|
||||
#endif /* USE_PARTIAL_CONNECT */
|
||||
|
||||
/**
|
||||
* For when the edge-net has holes in it-this connects them.
|
||||
*
|
||||
* \param use_partial_connect: Support for handling islands connected by only a single edge,
|
||||
* \note that this is quite slow so avoid using where possible.
|
||||
* \param mem_arena: Avoids many small allocs & should be cleared after each use.
|
||||
* take care since \a edge_net_new is stored in \a r_edge_net_new.
|
||||
*/
|
||||
bool BM_face_split_edgenet_connect_islands(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMEdge **edge_net_init,
|
||||
|
||||
@@ -20,6 +20,14 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Splits a face into many smaller faces defined by an edge-net.
|
||||
* handle customdata and degenerate cases.
|
||||
*
|
||||
* - Isolated holes or unsupported face configurations, will be ignored.
|
||||
* - Customdata calculations aren't efficient
|
||||
* (need to calculate weights for each vert).
|
||||
*/
|
||||
bool BM_face_split_edgenet(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMEdge **edge_net,
|
||||
@@ -27,6 +35,14 @@ bool BM_face_split_edgenet(BMesh *bm,
|
||||
BMFace ***r_face_arr,
|
||||
int *r_face_arr_len);
|
||||
|
||||
/**
|
||||
* For when the edge-net has holes in it-this connects them.
|
||||
*
|
||||
* \param use_partial_connect: Support for handling islands connected by only a single edge,
|
||||
* \note that this is quite slow so avoid using where possible.
|
||||
* \param mem_arena: Avoids many small allocs & should be cleared after each use.
|
||||
* take care since \a edge_net_new is stored in \a r_edge_net_new.
|
||||
*/
|
||||
bool BM_face_split_edgenet_connect_islands(BMesh *bm,
|
||||
BMFace *f,
|
||||
BMEdge **edge_net_init,
|
||||
|
||||
@@ -34,6 +34,12 @@
|
||||
* it can take most of the CPU time when running some tools. */
|
||||
# define BM_CHECK_ELEMENT(el) (void)(el)
|
||||
#else
|
||||
/**
|
||||
* Check the element is valid.
|
||||
*
|
||||
* BMESH_TODO, when this raises an error the output is incredibly confusing.
|
||||
* need to have some nice way to print/debug what the heck's going on.
|
||||
*/
|
||||
int bmesh_elem_check(void *element, const char htype);
|
||||
# define BM_CHECK_ELEMENT(el) \
|
||||
{ \
|
||||
@@ -86,6 +92,12 @@ enum {
|
||||
} \
|
||||
(void)0
|
||||
|
||||
/**
|
||||
* \brief POLY ROTATE PLANE
|
||||
*
|
||||
* Rotates a polygon so that its
|
||||
* normal is pointing towards the mesh Z axis
|
||||
*/
|
||||
void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts);
|
||||
|
||||
/* include the rest of our private declarations */
|
||||
|
||||
@@ -37,24 +37,6 @@
|
||||
#include "bmesh.h"
|
||||
#include "intern/bmesh_private.h"
|
||||
|
||||
/**
|
||||
* \brief Other Loop in Face Sharing an Edge
|
||||
*
|
||||
* Finds the other loop that shares \a v with \a e loop in \a f.
|
||||
* <pre>
|
||||
* +----------+
|
||||
* | |
|
||||
* | f |
|
||||
* | |
|
||||
* +----------+ <-- return the face loop of this vertex.
|
||||
* v --> e
|
||||
* ^ ^ <------- These vert args define direction
|
||||
* in the face to check.
|
||||
* The faces loop direction is ignored.
|
||||
* </pre>
|
||||
*
|
||||
* \note caller must ensure \a e is used in \a f
|
||||
*/
|
||||
BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v)
|
||||
{
|
||||
BMLoop *l = BM_face_edge_share_loop(f, e);
|
||||
@@ -62,38 +44,12 @@ BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v)
|
||||
return BM_loop_other_edge_loop(l, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* See #BM_face_other_edge_loop This is the same functionality
|
||||
* to be used when the edges loop is already known.
|
||||
*/
|
||||
BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
|
||||
{
|
||||
BLI_assert(BM_vert_in_edge(l->e, v));
|
||||
return l->v == v ? l->prev : l->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Other Loop in Face Sharing a Vertex
|
||||
*
|
||||
* Finds the other loop in a face.
|
||||
*
|
||||
* This function returns a loop in \a f that shares an edge with \a v
|
||||
* The direction is defined by \a v_prev, where the return value is
|
||||
* the loop of what would be 'v_next'
|
||||
* <pre>
|
||||
* +----------+ <-- return the face loop of this vertex.
|
||||
* | |
|
||||
* | f |
|
||||
* | |
|
||||
* +----------+
|
||||
* v_prev --> v
|
||||
* ^^^^^^ ^ <-- These vert args define direction
|
||||
* in the face to check.
|
||||
* The faces loop direction is ignored.
|
||||
* </pre>
|
||||
*
|
||||
* \note \a v_prev and \a v _implicitly_ define an edge.
|
||||
*/
|
||||
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
|
||||
{
|
||||
BMLoop *l_iter = BM_face_vert_share_loop(f, v);
|
||||
@@ -116,22 +72,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Other Loop in Face Sharing a Vert
|
||||
*
|
||||
* Finds the other loop that shares \a v with \a e loop in \a f.
|
||||
* <pre>
|
||||
* +----------+ <-- return the face loop of this vertex.
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* +----------+ <-- This vertex defines the direction.
|
||||
* l v
|
||||
* ^ <------- This loop defines both the face to search
|
||||
* and the edge, in combination with 'v'
|
||||
* The faces loop direction is ignored.
|
||||
* </pre>
|
||||
*/
|
||||
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
|
||||
{
|
||||
#if 0 /* works but slow */
|
||||
@@ -157,22 +97,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the other loop that uses this edge.
|
||||
*
|
||||
* In this case the loop defines the vertex,
|
||||
* the edge passed in defines the direction to step.
|
||||
*
|
||||
* <pre>
|
||||
* +----------+ <-- Return the face-loop of this vertex.
|
||||
* | |
|
||||
* | e | <-- This edge defines the direction.
|
||||
* | |
|
||||
* +----------+ <-- This loop defines the face and vertex..
|
||||
* l
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
|
||||
{
|
||||
BLI_assert(BM_vert_in_edge(e, l->v));
|
||||
@@ -187,9 +111,6 @@ BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if verts share a face.
|
||||
*/
|
||||
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
|
||||
{
|
||||
if (v_a->e && v_b->e) {
|
||||
@@ -255,9 +176,6 @@ BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given 2 verts, find the smallest face they share and give back both loops.
|
||||
*/
|
||||
BMFace *BM_vert_pair_share_face_by_len(
|
||||
BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
|
||||
{
|
||||
@@ -325,24 +243,12 @@ static float bm_face_calc_split_dot(BMLoop *l_a, BMLoop *l_b)
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a point is inside the corner defined by a loop
|
||||
* (within the 2 planes defined by the loops corner & face normal).
|
||||
*
|
||||
* \return signed, squared distance to the loops planes, less than 0.0 when outside.
|
||||
*/
|
||||
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3])
|
||||
{
|
||||
const float *axis = l->f->no;
|
||||
return dist_signed_squared_to_corner_v3v3v3(co, l->prev->v->co, l->v->co, l->next->v->co, axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a point is inside the edge defined by a loop
|
||||
* (within the plane defined by the loops edge & face normal).
|
||||
*
|
||||
* \return signed, squared distance to the edge plane, less than 0.0 when outside.
|
||||
*/
|
||||
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
|
||||
{
|
||||
const float *axis = l->f->no;
|
||||
@@ -356,13 +262,6 @@ float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
|
||||
return dist_signed_squared_to_plane_v3(co, plane);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given 2 verts,
|
||||
* find a face they share that has the lowest angle across these verts and give back both loops.
|
||||
*
|
||||
* This can be better than #BM_vert_pair_share_face_by_len
|
||||
* because concave splits are ranked lowest.
|
||||
*/
|
||||
BMFace *BM_vert_pair_share_face_by_angle(
|
||||
BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
|
||||
{
|
||||
@@ -409,25 +308,15 @@ BMFace *BM_vert_pair_share_face_by_angle(
|
||||
return f_cur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first loop of a vert. Uses the same initialization code for the first loop of the
|
||||
* iterator API
|
||||
*/
|
||||
BMLoop *BM_vert_find_first_loop(BMVert *v)
|
||||
{
|
||||
return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL;
|
||||
}
|
||||
/**
|
||||
* A version of #BM_vert_find_first_loop that ignores hidden loops.
|
||||
*/
|
||||
BMLoop *BM_vert_find_first_loop_visible(BMVert *v)
|
||||
{
|
||||
return v->e ? bmesh_disk_faceloop_find_first_visible(v->e, v) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the vertex is used in a given face.
|
||||
*/
|
||||
bool BM_vert_in_face(BMVert *v, BMFace *f)
|
||||
{
|
||||
BMLoop *l_iter, *l_first;
|
||||
@@ -452,10 +341,6 @@ bool BM_vert_in_face(BMVert *v, BMFace *f)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the number of vertices in an array
|
||||
* that appear in a given face
|
||||
*/
|
||||
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f)
|
||||
{
|
||||
BMLoop *l_iter, *l_first;
|
||||
@@ -496,9 +381,6 @@ int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if all verts are in the face.
|
||||
*/
|
||||
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
|
||||
{
|
||||
BMLoop *l_iter, *l_first;
|
||||
@@ -549,9 +431,6 @@ bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not a given edge is part of a given face.
|
||||
*/
|
||||
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
|
||||
{
|
||||
if (e->l) {
|
||||
@@ -568,22 +447,6 @@ bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a edge and a loop (assumes the edge is manifold). returns
|
||||
* the other faces loop, sharing the same vertex.
|
||||
*
|
||||
* <pre>
|
||||
* +-------------------+
|
||||
* | |
|
||||
* | |
|
||||
* |l_other <-- return |
|
||||
* +-------------------+ <-- A manifold edge between 2 faces
|
||||
* |l e <-- edge |
|
||||
* |^ <-------- loop |
|
||||
* | |
|
||||
* +-------------------+
|
||||
* </pre>
|
||||
*/
|
||||
BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
|
||||
{
|
||||
BMLoop *l_other;
|
||||
@@ -655,12 +518,6 @@ BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function takes a vertex at the center of a fan and returns the opposite edge in the fan.
|
||||
* All edges in the fan must be manifold, otherwise return NULL.
|
||||
*
|
||||
* \note This could (probably) be done more efficiently.
|
||||
*/
|
||||
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
|
||||
{
|
||||
BMLoop *l_a;
|
||||
@@ -707,28 +564,16 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns edge length
|
||||
*/
|
||||
float BM_edge_calc_length(const BMEdge *e)
|
||||
{
|
||||
return len_v3v3(e->v1->co, e->v2->co);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns edge length squared (for comparisons)
|
||||
*/
|
||||
float BM_edge_calc_length_squared(const BMEdge *e)
|
||||
{
|
||||
return len_squared_v3v3(e->v1->co, e->v2->co);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, since enough times we have an edge
|
||||
* and want to access 2 connected faces.
|
||||
*
|
||||
* \return true when only 2 faces are found.
|
||||
*/
|
||||
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
|
||||
{
|
||||
BMLoop *la, *lb;
|
||||
@@ -744,12 +589,6 @@ bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, since enough times we have an edge
|
||||
* and want to access 2 connected loops.
|
||||
*
|
||||
* \return true when only 2 faces are found.
|
||||
*/
|
||||
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
|
||||
{
|
||||
BMLoop *la, *lb;
|
||||
@@ -765,9 +604,6 @@ bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast alternative to `(BM_vert_edge_count(v) == 2)`.
|
||||
*/
|
||||
bool BM_vert_is_edge_pair(const BMVert *v)
|
||||
{
|
||||
const BMEdge *e = v->e;
|
||||
@@ -778,10 +614,6 @@ bool BM_vert_is_edge_pair(const BMVert *v)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast alternative to `(BM_vert_edge_count(v) == 2)`
|
||||
* that checks both edges connect to the same faces.
|
||||
*/
|
||||
bool BM_vert_is_edge_pair_manifold(const BMVert *v)
|
||||
{
|
||||
const BMEdge *e = v->e;
|
||||
@@ -794,11 +626,6 @@ bool BM_vert_is_edge_pair_manifold(const BMVert *v)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access a verts 2 connected edges.
|
||||
*
|
||||
* \return true when only 2 verts are found.
|
||||
*/
|
||||
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
|
||||
{
|
||||
BMEdge *e_a = v->e;
|
||||
@@ -816,9 +643,6 @@ bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of edges around this vertex.
|
||||
*/
|
||||
int BM_vert_edge_count(const BMVert *v)
|
||||
{
|
||||
return bmesh_disk_count(v);
|
||||
@@ -841,9 +665,6 @@ int BM_vert_edge_count_nonwire(const BMVert *v)
|
||||
}
|
||||
return count;
|
||||
}
|
||||
/**
|
||||
* Returns the number of faces around this edge
|
||||
*/
|
||||
int BM_edge_face_count(const BMEdge *e)
|
||||
{
|
||||
int count = 0;
|
||||
@@ -879,10 +700,6 @@ int BM_edge_face_count_at_most(const BMEdge *e, const int count_max)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of faces around this vert
|
||||
* length matches #BM_LOOPS_OF_VERT iterator
|
||||
*/
|
||||
int BM_vert_face_count(const BMVert *v)
|
||||
{
|
||||
return bmesh_disk_facevert_count(v);
|
||||
@@ -893,11 +710,6 @@ int BM_vert_face_count_at_most(const BMVert *v, int count_max)
|
||||
return bmesh_disk_facevert_count_at_most(v, count_max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the vertex is connected to _any_ faces.
|
||||
*
|
||||
* same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`.
|
||||
*/
|
||||
bool BM_vert_face_check(const BMVert *v)
|
||||
{
|
||||
if (v->e != NULL) {
|
||||
@@ -912,10 +724,6 @@ bool BM_vert_face_check(const BMVert *v)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not the vertex is part of a wire edge.
|
||||
* (ie: has no faces attached to it)
|
||||
*/
|
||||
bool BM_vert_is_wire(const BMVert *v)
|
||||
{
|
||||
if (v->e) {
|
||||
@@ -933,13 +741,6 @@ bool BM_vert_is_wire(const BMVert *v)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A vertex is non-manifold if it meets the following conditions:
|
||||
* 1: Loose - (has no edges/faces incident upon it).
|
||||
* 2: Joins two distinct regions - (two pyramids joined at the tip).
|
||||
* 3: Is part of an edge with more than 2 faces.
|
||||
* 4: Is part of a wire edge.
|
||||
*/
|
||||
bool BM_vert_is_manifold(const BMVert *v)
|
||||
{
|
||||
BMEdge *e_iter, *e_first, *e_prev;
|
||||
@@ -1064,9 +865,6 @@ static int bm_loop_region_count__clear(BMLoop *l)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of loops connected to this loop (not including disconnected regions).
|
||||
*/
|
||||
int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total)
|
||||
{
|
||||
const int count = bm_loop_region_count__recursive(l->e, l->v);
|
||||
@@ -1085,10 +883,6 @@ int BM_loop_region_loops_count(BMLoop *l)
|
||||
return BM_loop_region_loops_count_at_most(l, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #BM_vert_is_manifold
|
||||
* which only checks if we're connected to multiple isolated regions.
|
||||
*/
|
||||
bool BM_vert_is_manifold_region(const BMVert *v)
|
||||
{
|
||||
BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v);
|
||||
@@ -1100,10 +894,6 @@ bool BM_vert_is_manifold_region(const BMVert *v)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the edge is convex or concave
|
||||
* (depends on face winding)
|
||||
*/
|
||||
bool BM_edge_is_convex(const BMEdge *e)
|
||||
{
|
||||
if (BM_edge_is_manifold(e)) {
|
||||
@@ -1121,9 +911,6 @@ bool BM_edge_is_convex(const BMEdge *e)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return true when loop customdata is contiguous.
|
||||
*/
|
||||
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e,
|
||||
const int cd_loop_type,
|
||||
const int cd_loop_offset)
|
||||
@@ -1182,11 +969,6 @@ bool BM_vert_is_boundary(const BMVert *v)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of faces that are adjacent to both f1 and f2,
|
||||
* \note Could be sped up a bit by not using iterators and by tagging
|
||||
* faces on either side, then count the tags rather then searching.
|
||||
*/
|
||||
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b)
|
||||
{
|
||||
BMIter iter1, iter2;
|
||||
@@ -1205,9 +987,6 @@ int BM_face_share_face_count(BMFace *f_a, BMFace *f_b)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* same as #BM_face_share_face_count but returns a bool
|
||||
*/
|
||||
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
|
||||
{
|
||||
BMIter iter1, iter2;
|
||||
@@ -1225,9 +1004,6 @@ bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of edges two faces share (if any)
|
||||
*/
|
||||
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
|
||||
{
|
||||
BMLoop *l_iter;
|
||||
@@ -1244,9 +1020,6 @@ int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the faces share an edge
|
||||
*/
|
||||
bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
|
||||
{
|
||||
BMLoop *l_iter;
|
||||
@@ -1262,9 +1035,6 @@ bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of verts two faces share (if any).
|
||||
*/
|
||||
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
|
||||
{
|
||||
BMLoop *l_iter;
|
||||
@@ -1281,9 +1051,6 @@ int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the faces share a vert.
|
||||
*/
|
||||
bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
|
||||
{
|
||||
BMLoop *l_iter;
|
||||
@@ -1299,18 +1066,12 @@ bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when 2 loops share an edge (are adjacent in the face-fan)
|
||||
*/
|
||||
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b)
|
||||
{
|
||||
BLI_assert(l_a->v == l_b->v);
|
||||
return (ELEM(l_a->e, l_b->e, l_b->prev->e) || ELEM(l_b->e, l_a->e, l_a->prev->e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if e1 shares any faces with e2
|
||||
*/
|
||||
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
|
||||
{
|
||||
BMLoop *l;
|
||||
@@ -1329,9 +1090,6 @@ bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if e1 shares any quad faces with e2
|
||||
*/
|
||||
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
|
||||
{
|
||||
BMLoop *l;
|
||||
@@ -1352,17 +1110,11 @@ bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if e1 shares a vertex with e2
|
||||
*/
|
||||
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
|
||||
{
|
||||
return (e1->v1 == e2->v1 || e1->v1 == e2->v2 || e1->v2 == e2->v1 || e1->v2 == e2->v2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the shared vertex between the two edges or NULL
|
||||
*/
|
||||
BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
|
||||
{
|
||||
BLI_assert(e1 != e2);
|
||||
@@ -1375,14 +1127,6 @@ BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the Loop Shared by Edge and Vert
|
||||
*
|
||||
* Finds the loop used which uses \a in face loop \a l
|
||||
*
|
||||
* \note this function takes a loop rather than an edge
|
||||
* so we can select the face that the loop should be from.
|
||||
*/
|
||||
BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
|
||||
{
|
||||
BLI_assert(BM_vert_in_edge(l->e, v));
|
||||
@@ -1392,14 +1136,6 @@ BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
|
||||
return l->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the Loop Shared by Face and Vertex
|
||||
*
|
||||
* Finds the loop used which uses \a v in face loop \a l
|
||||
*
|
||||
* \note currently this just uses simple loop in future may be sped up
|
||||
* using radial vars
|
||||
*/
|
||||
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v)
|
||||
{
|
||||
BMLoop *l_first;
|
||||
@@ -1415,14 +1151,6 @@ BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the Loop Shared by Face and Edge
|
||||
*
|
||||
* Finds the loop used which uses \a e in face loop \a l
|
||||
*
|
||||
* \note currently this just uses simple loop in future may be sped up
|
||||
* using radial vars
|
||||
*/
|
||||
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
|
||||
{
|
||||
BMLoop *l_first;
|
||||
@@ -1438,18 +1166,6 @@ BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the verts of an edge as used in a face
|
||||
* if used in a face at all, otherwise just assign as used in the edge.
|
||||
*
|
||||
* Useful to get a deterministic winding order when calling
|
||||
* BM_face_create_ngon() on an arbitrary array of verts,
|
||||
* though be sure to pick an edge which has a face.
|
||||
*
|
||||
* \note This is in fact quite a simple check,
|
||||
* mainly include this function so the intent is more obvious.
|
||||
* We know these 2 verts will _always_ make up the loops edge
|
||||
*/
|
||||
void BM_edge_ordered_verts_ex(const BMEdge *edge,
|
||||
BMVert **r_v1,
|
||||
BMVert **r_v2,
|
||||
@@ -1466,9 +1182,6 @@ void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
|
||||
BM_edge_ordered_verts_ex(edge, r_v1, r_v2, edge->l);
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The previous loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
|
||||
*/
|
||||
BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
|
||||
{
|
||||
BMLoop *l_step = l->prev;
|
||||
@@ -1486,9 +1199,6 @@ BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
|
||||
return l_step;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The next loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
|
||||
*/
|
||||
BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
|
||||
{
|
||||
BMLoop *l_step = l->next;
|
||||
@@ -1506,10 +1216,6 @@ BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
|
||||
return l_step;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the loop is convex or concave
|
||||
* (depends on face normal)
|
||||
*/
|
||||
bool BM_loop_is_convex(const BMLoop *l)
|
||||
{
|
||||
float e_dir_prev[3];
|
||||
@@ -1522,26 +1228,11 @@ bool BM_loop_is_convex(const BMLoop *l)
|
||||
return dot_v3v3(l_no, l->f->no) > 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the angle between the previous and next loops
|
||||
* (angle at this loops face corner).
|
||||
*
|
||||
* \return angle in radians
|
||||
*/
|
||||
float BM_loop_calc_face_angle(const BMLoop *l)
|
||||
{
|
||||
return angle_v3v3v3(l->prev->v->co, l->v->co, l->next->v->co);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BM_loop_calc_face_normal
|
||||
*
|
||||
* Calculate the normal at this loop corner or fallback to the face normal on straight lines.
|
||||
*
|
||||
* \param l: The loop to calculate the normal at.
|
||||
* \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
|
||||
* \param r_normal: Resulting normal.
|
||||
*/
|
||||
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
|
||||
{
|
||||
/* NOTE: we cannot use result of normal_tri_v3 here to detect colinear vectors
|
||||
@@ -1571,9 +1262,6 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq,
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
|
||||
*/
|
||||
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
|
||||
const float normal_fallback[3],
|
||||
float const (*vertexCos)[3],
|
||||
@@ -1604,11 +1292,6 @@ float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* #BM_loop_calc_face_normal_safe_ex with predefined sane epsilon.
|
||||
*
|
||||
* Since this doesn't scale based on triangle size, fixed value works well.
|
||||
*/
|
||||
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
|
||||
{
|
||||
return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
|
||||
@@ -1623,15 +1306,6 @@ float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
|
||||
return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BM_loop_calc_face_normal
|
||||
*
|
||||
* Calculate the normal at this loop corner or fallback to the face normal on straight lines.
|
||||
*
|
||||
* \param l: The loop to calculate the normal at
|
||||
* \param r_normal: Resulting normal
|
||||
* \return The length of the cross product (double the area).
|
||||
*/
|
||||
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
|
||||
{
|
||||
float v1[3], v2[3];
|
||||
@@ -1646,14 +1320,6 @@ float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BM_loop_calc_face_direction
|
||||
*
|
||||
* Calculate the direction a loop is pointing.
|
||||
*
|
||||
* \param l: The loop to calculate the direction at
|
||||
* \param r_dir: Resulting direction
|
||||
*/
|
||||
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
|
||||
{
|
||||
float v_prev[3];
|
||||
@@ -1669,15 +1335,6 @@ void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
|
||||
normalize_v3(r_dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BM_loop_calc_face_tangent
|
||||
*
|
||||
* Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
|
||||
* This vector always points inward into the face.
|
||||
*
|
||||
* \param l: The loop to calculate the tangent at
|
||||
* \param r_tangent: Resulting tangent
|
||||
*/
|
||||
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
|
||||
{
|
||||
float v_prev[3];
|
||||
@@ -1708,14 +1365,6 @@ void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
|
||||
normalize_v3(r_tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH EDGE/FACE ANGLE
|
||||
*
|
||||
* Calculates the angle between two faces.
|
||||
* Assumes the face normals are correct.
|
||||
*
|
||||
* \return angle in radians
|
||||
*/
|
||||
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
|
||||
{
|
||||
if (BM_edge_is_manifold(e)) {
|
||||
@@ -1730,14 +1379,6 @@ float BM_edge_calc_face_angle(const BMEdge *e)
|
||||
return BM_edge_calc_face_angle_ex(e, DEG2RADF(90.0f));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH EDGE/FACE ANGLE
|
||||
*
|
||||
* Calculates the angle between two faces in world space.
|
||||
* Assumes the face normals are correct.
|
||||
*
|
||||
* \return angle in radians
|
||||
*/
|
||||
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e,
|
||||
const float imat3[3][3],
|
||||
const float fallback)
|
||||
@@ -1764,14 +1405,6 @@ float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, const float imat3[3][3
|
||||
return BM_edge_calc_face_angle_with_imat3_ex(e, imat3, DEG2RADF(90.0f));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH EDGE/FACE ANGLE
|
||||
*
|
||||
* Calculates the angle between two faces.
|
||||
* Assumes the face normals are correct.
|
||||
*
|
||||
* \return angle in radians
|
||||
*/
|
||||
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
|
||||
{
|
||||
if (BM_edge_is_manifold(e)) {
|
||||
@@ -1799,7 +1432,6 @@ float BM_edge_calc_face_angle_signed(const BMEdge *e)
|
||||
* used to get the face and winding direction.
|
||||
* \param r_tangent: The loop corner tangent to set
|
||||
*/
|
||||
|
||||
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
|
||||
{
|
||||
float tvec[3];
|
||||
@@ -1813,13 +1445,6 @@ void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_ta
|
||||
normalize_v3(r_tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH VERT/EDGE ANGLE
|
||||
*
|
||||
* Calculates the angle a verts 2 edges.
|
||||
*
|
||||
* \returns the angle in radians
|
||||
*/
|
||||
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
|
||||
{
|
||||
BMEdge *e1, *e2;
|
||||
@@ -1843,10 +1468,6 @@ float BM_vert_calc_edge_angle(const BMVert *v)
|
||||
return BM_vert_calc_edge_angle_ex(v, DEG2RADF(90.0f));
|
||||
}
|
||||
|
||||
/**
|
||||
* \note this isn't optimal to run on an array of verts,
|
||||
* see 'solidify_add_thickness' for a function which runs on an array.
|
||||
*/
|
||||
float BM_vert_calc_shell_factor(const BMVert *v)
|
||||
{
|
||||
BMIter iter;
|
||||
@@ -1865,8 +1486,6 @@ float BM_vert_calc_shell_factor(const BMVert *v)
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
/* alternate version of #BM_vert_calc_shell_factor which only
|
||||
* uses 'hflag' faces, but falls back to all if none found. */
|
||||
float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag)
|
||||
{
|
||||
BMIter iter;
|
||||
@@ -1896,10 +1515,6 @@ float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const cha
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* \note quite an obscure function.
|
||||
* used in bmesh operators that have a relative scale options,
|
||||
*/
|
||||
float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
|
||||
{
|
||||
BMIter iter;
|
||||
@@ -1920,9 +1535,6 @@ float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loop of the shortest edge in f.
|
||||
*/
|
||||
BMLoop *BM_face_find_shortest_loop(BMFace *f)
|
||||
{
|
||||
BMLoop *shortest_loop = NULL;
|
||||
@@ -1944,9 +1556,6 @@ BMLoop *BM_face_find_shortest_loop(BMFace *f)
|
||||
return shortest_loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loop of the longest edge in f.
|
||||
*/
|
||||
BMLoop *BM_face_find_longest_loop(BMFace *f)
|
||||
{
|
||||
BMLoop *longest_loop = NULL;
|
||||
@@ -2020,11 +1629,6 @@ BMEdge *BM_edge_exists(BMVert *v_a, BMVert *v_b)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns an edge sharing the same vertices as this one.
|
||||
* This isn't an invalid state but tools should clean up these cases before
|
||||
* returning the mesh to the user.
|
||||
*/
|
||||
BMEdge *BM_edge_find_double(BMEdge *e)
|
||||
{
|
||||
BMVert *v = e->v1;
|
||||
@@ -2042,10 +1646,6 @@ BMEdge *BM_edge_find_double(BMEdge *e)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only #BMEdge.l access us needed, however when we want the first visible loop,
|
||||
* a utility function is needed.
|
||||
*/
|
||||
BMLoop *BM_edge_find_first_loop_visible(BMEdge *e)
|
||||
{
|
||||
if (e->l != NULL) {
|
||||
@@ -2060,13 +1660,6 @@ BMLoop *BM_edge_find_first_loop_visible(BMEdge *e)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of vertices (varr), find out if
|
||||
* there is a face with exactly those vertices
|
||||
* (and only those vertices).
|
||||
*
|
||||
* \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
|
||||
*/
|
||||
BMFace *BM_face_exists(BMVert **varr, int len)
|
||||
{
|
||||
if (varr[0]->e) {
|
||||
@@ -2115,9 +1708,6 @@ BMFace *BM_face_exists(BMVert **varr, int len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the face has an exact duplicate (both winding directions).
|
||||
*/
|
||||
BMFace *BM_face_find_double(BMFace *f)
|
||||
{
|
||||
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
|
||||
@@ -2150,18 +1740,6 @@ BMFace *BM_face_find_double(BMFace *f)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of vertices and edges (\a varr, \a earr), find out if
|
||||
* all those vertices are filled in by existing faces that _only_ use those vertices.
|
||||
*
|
||||
* This is for use in cases where creating a face is possible but would result in
|
||||
* many overlapping faces.
|
||||
*
|
||||
* An example of how this is used: when 2 tri's are selected that share an edge,
|
||||
* pressing Fkey would make a new overlapping quad (without a check like this)
|
||||
*
|
||||
* \a earr and \a varr can be in any order, however they _must_ form a closed loop.
|
||||
*/
|
||||
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
|
||||
{
|
||||
BMFace *f;
|
||||
@@ -2270,7 +1848,6 @@ finally:
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* same as 'BM_face_exists_multi' but built vert array from edges */
|
||||
bool BM_face_exists_multi_edge(BMEdge **earr, int len)
|
||||
{
|
||||
BMVert **varr = BLI_array_alloca(varr, len);
|
||||
@@ -2284,20 +1861,6 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len)
|
||||
return BM_face_exists_multi(varr, earr, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of vertices (varr), find out if
|
||||
* all those vertices overlap an existing face.
|
||||
*
|
||||
* \note The face may contain other verts \b not in \a varr.
|
||||
*
|
||||
* \note Its possible there are more than one overlapping faces,
|
||||
* in this case the first one found will be returned.
|
||||
*
|
||||
* \param varr: Array of unordered verts.
|
||||
* \param len: \a varr array length.
|
||||
* \return The face or NULL.
|
||||
*/
|
||||
|
||||
BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
|
||||
{
|
||||
BMIter viter;
|
||||
@@ -2336,14 +1899,6 @@ BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
|
||||
return f_overlap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of vertices (varr), find out if
|
||||
* there is a face that uses vertices only from this list
|
||||
* (that the face is a subset or made from the vertices given).
|
||||
*
|
||||
* \param varr: Array of unordered verts.
|
||||
* \param len: varr array length.
|
||||
*/
|
||||
bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
|
||||
{
|
||||
BMIter viter;
|
||||
@@ -2477,7 +2032,6 @@ bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* convenience functions for checking flags */
|
||||
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
|
||||
{
|
||||
return (BM_elem_flag_test(e->v1, hflag) || BM_elem_flag_test(e->v2, hflag));
|
||||
@@ -2527,9 +2081,6 @@ bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use within assert's to check normals are valid.
|
||||
*/
|
||||
bool BM_face_is_normal_valid(const BMFace *f)
|
||||
{
|
||||
const float eps = 0.0001f;
|
||||
@@ -2592,22 +2143,6 @@ double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
|
||||
}
|
||||
|
||||
/* NOTE: almost duplicate of #BM_mesh_calc_edge_groups, keep in sync. */
|
||||
/**
|
||||
* Calculate isolated groups of faces with optional filtering.
|
||||
*
|
||||
* \param bm: the BMesh.
|
||||
* \param r_groups_array: Array of ints to fill in, length of bm->totface
|
||||
* (or when hflag_test is set, the number of flagged faces).
|
||||
* \param r_group_index: index, length pairs into \a r_groups_array, size of return value
|
||||
* int pairs: (array_start, array_length).
|
||||
* \param filter_fn: Filter the edge-loops or vert-loops we step over (depends on \a htype_step).
|
||||
* \param user_data: Optional user data for \a filter_fn, can be NULL.
|
||||
* \param hflag_test: Optional flag to test faces,
|
||||
* use to exclude faces from the calculation, 0 for all faces.
|
||||
* \param htype_step: BM_VERT to walk over face-verts, BM_EDGE to walk over faces edges
|
||||
* (having both set is supported too).
|
||||
* \return The number of groups found.
|
||||
*/
|
||||
int BM_mesh_calc_face_groups(BMesh *bm,
|
||||
int *r_groups_array,
|
||||
int (**r_group_index)[2],
|
||||
@@ -2756,24 +2291,6 @@ int BM_mesh_calc_face_groups(BMesh *bm,
|
||||
}
|
||||
|
||||
/* NOTE: almost duplicate of #BM_mesh_calc_face_groups, keep in sync. */
|
||||
/**
|
||||
* Calculate isolated groups of edges with optional filtering.
|
||||
*
|
||||
* \param bm: the BMesh.
|
||||
* \param r_groups_array: Array of ints to fill in, length of bm->totedge
|
||||
* (or when hflag_test is set, the number of flagged edges).
|
||||
* \param r_group_index: index, length pairs into \a r_groups_array, size of return value
|
||||
* int pairs: (array_start, array_length).
|
||||
* \param filter_fn: Filter the edges or verts we step over (depends on \a htype_step)
|
||||
* as to which types we deal with.
|
||||
* \param user_data: Optional user data for \a filter_fn, can be NULL.
|
||||
* \param hflag_test: Optional flag to test edges,
|
||||
* use to exclude edges from the calculation, 0 for all edges.
|
||||
* \return The number of groups found.
|
||||
*
|
||||
* \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
|
||||
* since we always walk over verts.
|
||||
*/
|
||||
int BM_mesh_calc_edge_groups(BMesh *bm,
|
||||
int *r_groups_array,
|
||||
int (**r_group_index)[2],
|
||||
@@ -2892,13 +2409,6 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
|
||||
return group_curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an alternative to #BM_mesh_calc_edge_groups.
|
||||
*
|
||||
* While we could call this, then create vertex & face arrays,
|
||||
* it requires looping over geometry connectivity twice,
|
||||
* this slows down edit-mesh separate by loose parts, see: T70864.
|
||||
*/
|
||||
int BM_mesh_calc_edge_groups_as_arrays(
|
||||
BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int (**r_groups)[3])
|
||||
{
|
||||
|
||||
@@ -20,11 +20,24 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns true if the vertex is used in a given face.
|
||||
*/
|
||||
bool BM_vert_in_face(BMVert *v, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Compares the number of vertices in an array
|
||||
* that appear in a given face
|
||||
*/
|
||||
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Return true if all verts are in the face.
|
||||
*/
|
||||
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Returns whether or not a given edge is part of a given face.
|
||||
*/
|
||||
bool BM_edge_in_face(const BMEdge *e, const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
@@ -35,27 +48,151 @@ BLI_INLINE bool BM_verts_in_edge(const BMVert *v1,
|
||||
const BMVert *v2,
|
||||
const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Returns edge length
|
||||
*/
|
||||
float BM_edge_calc_length(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Returns edge length squared (for comparisons)
|
||||
*/
|
||||
float BM_edge_calc_length_squared(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Utility function, since enough times we have an edge
|
||||
* and want to access 2 connected faces.
|
||||
*
|
||||
* \return true when only 2 faces are found.
|
||||
*/
|
||||
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb) ATTR_NONNULL();
|
||||
/**
|
||||
* Utility function, since enough times we have an edge
|
||||
* and want to access 2 connected loops.
|
||||
*
|
||||
* \return true when only 2 faces are found.
|
||||
*/
|
||||
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb) ATTR_NONNULL();
|
||||
BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Given a edge and a loop (assumes the edge is manifold). returns
|
||||
* the other faces loop, sharing the same vertex.
|
||||
*
|
||||
* <pre>
|
||||
* +-------------------+
|
||||
* | |
|
||||
* | |
|
||||
* |l_other <-- return |
|
||||
* +-------------------+ <-- A manifold edge between 2 faces
|
||||
* |l e <-- edge |
|
||||
* |^ <-------- loop |
|
||||
* | |
|
||||
* +-------------------+
|
||||
* </pre>
|
||||
*/
|
||||
BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \brief Other Loop in Face Sharing an Edge
|
||||
*
|
||||
* Finds the other loop that shares \a v with \a e loop in \a f.
|
||||
* <pre>
|
||||
* +----------+
|
||||
* | |
|
||||
* | f |
|
||||
* | |
|
||||
* +----------+ <-- return the face loop of this vertex.
|
||||
* v --> e
|
||||
* ^ ^ <------- These vert args define direction
|
||||
* in the face to check.
|
||||
* The faces loop direction is ignored.
|
||||
* </pre>
|
||||
*
|
||||
* \note caller must ensure \a e is used in \a f
|
||||
*/
|
||||
BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* See #BM_face_other_edge_loop This is the same functionality
|
||||
* to be used when the edges loop is already known.
|
||||
*/
|
||||
BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \brief Other Loop in Face Sharing a Vertex
|
||||
*
|
||||
* Finds the other loop in a face.
|
||||
*
|
||||
* This function returns a loop in \a f that shares an edge with \a v
|
||||
* The direction is defined by \a v_prev, where the return value is
|
||||
* the loop of what would be 'v_next'
|
||||
* <pre>
|
||||
* +----------+ <-- return the face loop of this vertex.
|
||||
* | |
|
||||
* | f |
|
||||
* | |
|
||||
* +----------+
|
||||
* v_prev --> v
|
||||
* ^^^^^^ ^ <-- These vert args define direction
|
||||
* in the face to check.
|
||||
* The faces loop direction is ignored.
|
||||
* </pre>
|
||||
*
|
||||
* \note \a v_prev and \a v _implicitly_ define an edge.
|
||||
*/
|
||||
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Return the other loop that uses this edge.
|
||||
*
|
||||
* In this case the loop defines the vertex,
|
||||
* the edge passed in defines the direction to step.
|
||||
*
|
||||
* <pre>
|
||||
* +----------+ <-- Return the face-loop of this vertex.
|
||||
* | |
|
||||
* | e | <-- This edge defines the direction.
|
||||
* | |
|
||||
* +----------+ <-- This loop defines the face and vertex..
|
||||
* l
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* \brief Other Loop in Face Sharing a Vert
|
||||
*
|
||||
* Finds the other loop that shares \a v with \a e loop in \a f.
|
||||
* <pre>
|
||||
* +----------+ <-- return the face loop of this vertex.
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* +----------+ <-- This vertex defines the direction.
|
||||
* l v
|
||||
* ^ <------- This loop defines both the face to search
|
||||
* and the edge, in combination with 'v'
|
||||
* The faces loop direction is ignored.
|
||||
* </pre>
|
||||
*/
|
||||
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Get the first loop of a vert. Uses the same initialization code for the first loop of the
|
||||
* iterator API
|
||||
*/
|
||||
BMLoop *BM_vert_find_first_loop(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* A version of #BM_vert_find_first_loop that ignores hidden loops.
|
||||
*/
|
||||
BMLoop *BM_vert_find_first_loop_visible(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Only #BMEdge.l access us needed, however when we want the first visible loop,
|
||||
* a utility function is needed.
|
||||
*/
|
||||
BMLoop *BM_edge_find_first_loop_visible(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Check if verts share a face.
|
||||
*/
|
||||
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
|
||||
@@ -70,11 +207,21 @@ BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
|
||||
void *user_data,
|
||||
BMLoop **r_l_a,
|
||||
BMLoop **r_l_b) ATTR_NONNULL(1, 2, 4, 6, 7);
|
||||
/**
|
||||
* Given 2 verts, find the smallest face they share and give back both loops.
|
||||
*/
|
||||
BMFace *BM_vert_pair_share_face_by_len(BMVert *v_a,
|
||||
BMVert *v_b,
|
||||
BMLoop **r_l_a,
|
||||
BMLoop **r_l_b,
|
||||
const bool allow_adjacent) ATTR_NONNULL();
|
||||
/**
|
||||
* Given 2 verts,
|
||||
* find a face they share that has the lowest angle across these verts and give back both loops.
|
||||
*
|
||||
* This can be better than #BM_vert_pair_share_face_by_len
|
||||
* because concave splits are ranked lowest.
|
||||
*/
|
||||
BMFace *BM_vert_pair_share_face_by_angle(BMVert *v_a,
|
||||
BMVert *v_b,
|
||||
BMLoop **r_l_a,
|
||||
@@ -92,57 +239,169 @@ int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NON
|
||||
#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == (n) + 1)
|
||||
int BM_vert_edge_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Returns the number of edges around this vertex.
|
||||
*/
|
||||
int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == n)
|
||||
#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == (n) + 1)
|
||||
int BM_edge_face_count_at_most(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Returns the number of faces around this edge
|
||||
*/
|
||||
int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == n)
|
||||
#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == (n) + 1)
|
||||
int BM_vert_face_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Returns the number of faces around this vert
|
||||
* length matches #BM_LOOPS_OF_VERT iterator
|
||||
*/
|
||||
int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* The function takes a vertex at the center of a fan and returns the opposite edge in the fan.
|
||||
* All edges in the fan must be manifold, otherwise return NULL.
|
||||
*
|
||||
* \note This could (probably) be done more efficiently.
|
||||
*/
|
||||
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Fast alternative to `(BM_vert_edge_count(v) == 2)`.
|
||||
*/
|
||||
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Fast alternative to `(BM_vert_edge_count(v) == 2)`
|
||||
* that checks both edges connect to the same faces.
|
||||
*/
|
||||
bool BM_vert_is_edge_pair_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Access a verts 2 connected edges.
|
||||
*
|
||||
* \return true when only 2 verts are found.
|
||||
*/
|
||||
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b);
|
||||
/**
|
||||
* Return true if the vertex is connected to _any_ faces.
|
||||
*
|
||||
* same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`.
|
||||
*/
|
||||
bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Tests whether or not the vertex is part of a wire edge.
|
||||
* (ie: has no faces attached to it)
|
||||
*/
|
||||
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* A vertex is non-manifold if it meets the following conditions:
|
||||
* 1: Loose - (has no edges/faces incident upon it).
|
||||
* 2: Joins two distinct regions - (two pyramids joined at the tip).
|
||||
* 3: Is part of an edge with more than 2 faces.
|
||||
* 4: Is part of a wire edge.
|
||||
*/
|
||||
bool BM_vert_is_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* A version of #BM_vert_is_manifold
|
||||
* which only checks if we're connected to multiple isolated regions.
|
||||
*/
|
||||
bool BM_vert_is_manifold_region(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
bool BM_vert_is_boundary(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Check if the edge is convex or concave
|
||||
* (depends on face winding)
|
||||
*/
|
||||
bool BM_edge_is_convex(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \return true when loop customdata is contiguous.
|
||||
*/
|
||||
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e,
|
||||
const int cd_loop_type,
|
||||
const int cd_loop_offset) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* The number of loops connected to this loop (not including disconnected regions).
|
||||
*/
|
||||
int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL(1);
|
||||
int BM_loop_region_loops_count(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
|
||||
/**
|
||||
* Check if the loop is convex or concave
|
||||
* (depends on face normal)
|
||||
*/
|
||||
bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Check if a point is inside the corner defined by a loop
|
||||
* (within the 2 planes defined by the loops corner & face normal).
|
||||
*
|
||||
* \return signed, squared distance to the loops planes, less than 0.0 when outside.
|
||||
*/
|
||||
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Check if a point is inside the edge defined by a loop
|
||||
* (within the plane defined by the loops edge & face normal).
|
||||
*
|
||||
* \return signed, squared distance to the edge plane, less than 0.0 when outside.
|
||||
*/
|
||||
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* \return The previous loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
|
||||
*/
|
||||
BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
|
||||
/**
|
||||
* \return The next loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
|
||||
*/
|
||||
BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
|
||||
|
||||
/**
|
||||
* Calculates the angle between the previous and next loops
|
||||
* (angle at this loops face corner).
|
||||
*
|
||||
* \return angle in radians
|
||||
*/
|
||||
float BM_loop_calc_face_angle(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \brief BM_loop_calc_face_normal
|
||||
*
|
||||
* Calculate the normal at this loop corner or fallback to the face normal on straight lines.
|
||||
*
|
||||
* \param l: The loop to calculate the normal at
|
||||
* \param r_normal: Resulting normal
|
||||
* \return The length of the cross product (double the area).
|
||||
*/
|
||||
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* #BM_loop_calc_face_normal_safe_ex with predefined sane epsilon.
|
||||
*
|
||||
* Since this doesn't scale based on triangle size, fixed value works well.
|
||||
*/
|
||||
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
|
||||
/**
|
||||
* \brief BM_loop_calc_face_normal
|
||||
*
|
||||
* Calculate the normal at this loop corner or fallback to the face normal on straight lines.
|
||||
*
|
||||
* \param l: The loop to calculate the normal at.
|
||||
* \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
|
||||
* \param r_normal: Resulting normal.
|
||||
*/
|
||||
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3])
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
|
||||
*/
|
||||
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
|
||||
const float normal_fallback[3],
|
||||
float const (*vertexCos)[3],
|
||||
@@ -153,15 +412,56 @@ float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
|
||||
float const (*vertexCos)[3],
|
||||
float r_normal[3]) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* \brief BM_loop_calc_face_direction
|
||||
*
|
||||
* Calculate the direction a loop is pointing.
|
||||
*
|
||||
* \param l: The loop to calculate the direction at
|
||||
* \param r_dir: Resulting direction
|
||||
*/
|
||||
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3]);
|
||||
/**
|
||||
* \brief BM_loop_calc_face_tangent
|
||||
*
|
||||
* Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
|
||||
* This vector always points inward into the face.
|
||||
*
|
||||
* \param l: The loop to calculate the tangent at
|
||||
* \param r_tangent: Resulting tangent
|
||||
*/
|
||||
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
|
||||
|
||||
/**
|
||||
* \brief BMESH EDGE/FACE ANGLE
|
||||
*
|
||||
* Calculates the angle between two faces.
|
||||
* Assumes the face normals are correct.
|
||||
*
|
||||
* \return angle in radians
|
||||
*/
|
||||
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \brief BMESH EDGE/FACE ANGLE
|
||||
*
|
||||
* Calculates the angle between two faces.
|
||||
* Assumes the face normals are correct.
|
||||
*
|
||||
* \return angle in radians
|
||||
*/
|
||||
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e,
|
||||
const float fallback) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* \brief BMESH EDGE/FACE ANGLE
|
||||
*
|
||||
* Calculates the angle between two faces in world space.
|
||||
* Assumes the face normals are correct.
|
||||
*
|
||||
* \return angle in radians
|
||||
*/
|
||||
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e,
|
||||
const float imat3[3][3],
|
||||
const float fallback) ATTR_WARN_UNUSED_RESULT
|
||||
@@ -173,52 +473,195 @@ float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT AT
|
||||
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
|
||||
ATTR_NONNULL();
|
||||
float BM_vert_calc_edge_angle(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \brief BMESH VERT/EDGE ANGLE
|
||||
*
|
||||
* Calculates the angle a verts 2 edges.
|
||||
*
|
||||
* \returns the angle in radians
|
||||
*/
|
||||
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* \note this isn't optimal to run on an array of verts,
|
||||
* see 'solidify_add_thickness' for a function which runs on an array.
|
||||
*/
|
||||
float BM_vert_calc_shell_factor(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/* alternate version of #BM_vert_calc_shell_factor which only
|
||||
* uses 'hflag' faces, but falls back to all if none found. */
|
||||
float BM_vert_calc_shell_factor_ex(const BMVert *v,
|
||||
const float no[3],
|
||||
const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \note quite an obscure function.
|
||||
* used in bmesh operators that have a relative scale options,
|
||||
*/
|
||||
float BM_vert_calc_median_tagged_edge_length(const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Returns the loop of the shortest edge in f.
|
||||
*/
|
||||
BMLoop *BM_face_find_shortest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Returns the loop of the longest edge in f.
|
||||
*/
|
||||
BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
BMEdge *BM_edge_exists(BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Returns an edge sharing the same vertices as this one.
|
||||
* This isn't an invalid state but tools should clean up these cases before
|
||||
* returning the mesh to the user.
|
||||
*/
|
||||
BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Given a set of vertices (varr), find out if
|
||||
* there is a face with exactly those vertices
|
||||
* (and only those vertices).
|
||||
*
|
||||
* \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
|
||||
*/
|
||||
BMFace *BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1);
|
||||
/**
|
||||
* Check if the face has an exact duplicate (both winding directions).
|
||||
*/
|
||||
BMFace *BM_face_find_double(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Given a set of vertices and edges (\a varr, \a earr), find out if
|
||||
* all those vertices are filled in by existing faces that _only_ use those vertices.
|
||||
*
|
||||
* This is for use in cases where creating a face is possible but would result in
|
||||
* many overlapping faces.
|
||||
*
|
||||
* An example of how this is used: when 2 tri's are selected that share an edge,
|
||||
* pressing Fkey would make a new overlapping quad (without a check like this)
|
||||
*
|
||||
* \a earr and \a varr can be in any order, however they _must_ form a closed loop.
|
||||
*/
|
||||
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/* same as 'BM_face_exists_multi' but built vert array from edges */
|
||||
bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Given a set of vertices (varr), find out if
|
||||
* all those vertices overlap an existing face.
|
||||
*
|
||||
* \note The face may contain other verts \b not in \a varr.
|
||||
*
|
||||
* \note Its possible there are more than one overlapping faces,
|
||||
* in this case the first one found will be returned.
|
||||
*
|
||||
* \param varr: Array of unordered verts.
|
||||
* \param len: \a varr array length.
|
||||
* \return The face or NULL.
|
||||
*/
|
||||
BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* Given a set of vertices (varr), find out if
|
||||
* there is a face that uses vertices only from this list
|
||||
* (that the face is a subset or made from the vertices given).
|
||||
*
|
||||
* \param varr: Array of unordered verts.
|
||||
* \param len: varr array length.
|
||||
*/
|
||||
bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Returns the number of faces that are adjacent to both f1 and f2,
|
||||
* \note Could be sped up a bit by not using iterators and by tagging
|
||||
* faces on either side, then count the tags rather then searching.
|
||||
*/
|
||||
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Counts the number of edges two faces share (if any)
|
||||
*/
|
||||
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Counts the number of verts two faces share (if any).
|
||||
*/
|
||||
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* same as #BM_face_share_face_count but returns a bool
|
||||
*/
|
||||
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Returns true if the faces share an edge
|
||||
*/
|
||||
bool BM_face_share_edge_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Returns true if the faces share a vert.
|
||||
*/
|
||||
bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Returns true when 2 loops share an edge (are adjacent in the face-fan)
|
||||
*/
|
||||
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Test if e1 shares any faces with e2
|
||||
*/
|
||||
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Test if e1 shares any quad faces with e2
|
||||
*/
|
||||
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* Tests to see if e1 shares a vertex with e2
|
||||
*/
|
||||
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Return the shared vertex between the two edges or NULL
|
||||
*/
|
||||
BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \brief Return the Loop Shared by Edge and Vert
|
||||
*
|
||||
* Finds the loop used which uses \a in face loop \a l
|
||||
*
|
||||
* \note this function takes a loop rather than an edge
|
||||
* so we can select the face that the loop should be from.
|
||||
*/
|
||||
BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \brief Return the Loop Shared by Face and Vertex
|
||||
*
|
||||
* Finds the loop used which uses \a v in face loop \a l
|
||||
*
|
||||
* \note currently this just uses simple loop in future may be sped up
|
||||
* using radial vars
|
||||
*/
|
||||
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \brief Return the Loop Shared by Face and Edge
|
||||
*
|
||||
* Finds the loop used which uses \a e in face loop \a l
|
||||
*
|
||||
* \note currently this just uses simple loop in future may be sped up
|
||||
* using radial vars
|
||||
*/
|
||||
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2) ATTR_NONNULL();
|
||||
/**
|
||||
* Returns the verts of an edge as used in a face
|
||||
* if used in a face at all, otherwise just assign as used in the edge.
|
||||
*
|
||||
* Useful to get a deterministic winding order when calling
|
||||
* BM_face_create_ngon() on an arbitrary array of verts,
|
||||
* though be sure to pick an edge which has a face.
|
||||
*
|
||||
* \note This is in fact quite a simple check,
|
||||
* mainly include this function so the intent is more obvious.
|
||||
* We know these 2 verts will _always_ make up the loops edge
|
||||
*/
|
||||
void BM_edge_ordered_verts_ex(const BMEdge *edge,
|
||||
BMVert **r_v1,
|
||||
BMVert **r_v2,
|
||||
@@ -234,6 +677,7 @@ bool BM_edge_is_all_face_flag_test(const BMEdge *e,
|
||||
const char hflag,
|
||||
const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/* convenience functions for checking flags */
|
||||
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
|
||||
@@ -246,10 +690,29 @@ bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_
|
||||
bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Use within assert's to check normals are valid.
|
||||
*/
|
||||
bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
double BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Calculate isolated groups of faces with optional filtering.
|
||||
*
|
||||
* \param bm: the BMesh.
|
||||
* \param r_groups_array: Array of ints to fill in, length of bm->totface
|
||||
* (or when hflag_test is set, the number of flagged faces).
|
||||
* \param r_group_index: index, length pairs into \a r_groups_array, size of return value
|
||||
* int pairs: (array_start, array_length).
|
||||
* \param filter_fn: Filter the edge-loops or vert-loops we step over (depends on \a htype_step).
|
||||
* \param user_data: Optional user data for \a filter_fn, can be NULL.
|
||||
* \param hflag_test: Optional flag to test faces,
|
||||
* use to exclude faces from the calculation, 0 for all faces.
|
||||
* \param htype_step: BM_VERT to walk over face-verts, BM_EDGE to walk over faces edges
|
||||
* (having both set is supported too).
|
||||
* \return The number of groups found.
|
||||
*/
|
||||
int BM_mesh_calc_face_groups(BMesh *bm,
|
||||
int *r_groups_array,
|
||||
int (**r_group_index)[2],
|
||||
@@ -258,6 +721,24 @@ int BM_mesh_calc_face_groups(BMesh *bm,
|
||||
void *user_data,
|
||||
const char hflag_test,
|
||||
const char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
|
||||
/**
|
||||
* Calculate isolated groups of edges with optional filtering.
|
||||
*
|
||||
* \param bm: the BMesh.
|
||||
* \param r_groups_array: Array of ints to fill in, length of bm->totedge
|
||||
* (or when hflag_test is set, the number of flagged edges).
|
||||
* \param r_group_index: index, length pairs into \a r_groups_array, size of return value
|
||||
* int pairs: (array_start, array_length).
|
||||
* \param filter_fn: Filter the edges or verts we step over (depends on \a htype_step)
|
||||
* as to which types we deal with.
|
||||
* \param user_data: Optional user data for \a filter_fn, can be NULL.
|
||||
* \param hflag_test: Optional flag to test edges,
|
||||
* use to exclude edges from the calculation, 0 for all edges.
|
||||
* \return The number of groups found.
|
||||
*
|
||||
* \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
|
||||
* since we always walk over verts.
|
||||
*/
|
||||
int BM_mesh_calc_edge_groups(BMesh *bm,
|
||||
int *r_groups_array,
|
||||
int (**r_group_index)[2],
|
||||
@@ -265,6 +746,13 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
|
||||
void *user_data,
|
||||
const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
|
||||
|
||||
/**
|
||||
* This is an alternative to #BM_mesh_calc_edge_groups.
|
||||
*
|
||||
* While we could call this, then create vertex & face arrays,
|
||||
* it requires looping over geometry connectivity twice,
|
||||
* this slows down edit-mesh separate by loose parts, see: T70864.
|
||||
*/
|
||||
int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm,
|
||||
BMVert **verts,
|
||||
BMEdge **edges,
|
||||
|
||||
@@ -48,14 +48,6 @@ static void uv_aspect(const BMLoop *l,
|
||||
*/
|
||||
#define UV_ASPECT(l, r_uv) uv_aspect(l, aspect, cd_loop_uv_offset, r_uv)
|
||||
|
||||
/**
|
||||
* Computes the UV center of a face, using the mean average weighted by edge length.
|
||||
*
|
||||
* See #BM_face_calc_center_median_weighted for matching spatial functionality.
|
||||
*
|
||||
* \param aspect: Calculate the center scaling by these values, and finally dividing.
|
||||
* Since correct weighting depends on having the correct aspect.
|
||||
*/
|
||||
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
|
||||
const float aspect[2],
|
||||
const int cd_loop_uv_offset,
|
||||
@@ -109,9 +101,6 @@ void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset,
|
||||
mul_v2_fl(r_cent, 1.0f / (float)f->len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the UV cross product (use the sign to check the winding).
|
||||
*/
|
||||
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset)
|
||||
{
|
||||
float(*uvs)[2] = BLI_array_alloca(uvs, f->len);
|
||||
@@ -148,9 +137,6 @@ void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two loops that share an edge also have the same UV coordinates.
|
||||
*/
|
||||
bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
|
||||
{
|
||||
BLI_assert(l_a->e == l_b->e);
|
||||
@@ -165,9 +151,6 @@ bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_
|
||||
equals_v2v2(luv_a_next->uv, luv_b_next->uv));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two loops that share a vertex also have the same UV coordinates.
|
||||
*/
|
||||
bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
|
||||
{
|
||||
BLI_assert(l_a->v == l_b->v);
|
||||
@@ -179,9 +162,6 @@ bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two loops that share a vertex also have the same UV coordinates.
|
||||
*/
|
||||
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
|
||||
{
|
||||
BLI_assert(l_a->v == l_b->v);
|
||||
@@ -204,9 +184,6 @@ bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the point is inside the UV face.
|
||||
*/
|
||||
bool BM_face_uv_point_inside_test(const BMFace *f, const float co[2], const int cd_loop_uv_offset)
|
||||
{
|
||||
float(*projverts)[2] = BLI_array_alloca(projverts, f->len);
|
||||
|
||||
@@ -27,6 +27,14 @@ float BM_loop_uv_calc_edge_length(const BMLoop *l,
|
||||
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Computes the UV center of a face, using the mean average weighted by edge length.
|
||||
*
|
||||
* See #BM_face_calc_center_median_weighted for matching spatial functionality.
|
||||
*
|
||||
* \param aspect: Calculate the center scaling by these values, and finally dividing.
|
||||
* Since correct weighting depends on having the correct aspect.
|
||||
*/
|
||||
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
|
||||
const float aspect[2],
|
||||
const int cd_loop_uv_offset,
|
||||
@@ -34,6 +42,9 @@ void BM_face_uv_calc_center_median_weighted(const BMFace *f,
|
||||
void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2])
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Calculate the UV cross product (use the sign to check the winding).
|
||||
*/
|
||||
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
@@ -46,19 +57,31 @@ bool BM_loop_uv_share_edge_check_with_limit(BMLoop *l_a,
|
||||
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Check if two loops that share an edge also have the same UV coordinates.
|
||||
*/
|
||||
bool BM_loop_uv_share_edge_check(BMLoop *l_a,
|
||||
BMLoop *l_b,
|
||||
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Check if two loops that share a vertex also have the same UV coordinates.
|
||||
*/
|
||||
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Check if two loops that share a vertex also have the same UV coordinates.
|
||||
*/
|
||||
bool BM_loop_uv_share_vert_check(BMLoop *l_a,
|
||||
BMLoop *l_b,
|
||||
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Check if the point is inside the UV face.
|
||||
*/
|
||||
bool BM_face_uv_point_inside_test(const BMFace *f,
|
||||
const float co[2],
|
||||
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
|
||||
|
||||
@@ -47,11 +47,6 @@ void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles all connected data, use with care.
|
||||
*
|
||||
* Assumes caller has setup correct state before the swap is done.
|
||||
*/
|
||||
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
|
||||
{
|
||||
/* swap out loops */
|
||||
@@ -268,14 +263,6 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief DISK COUNT FACE VERT
|
||||
*
|
||||
* Counts the number of loop users
|
||||
* for this vertex. Note that this is
|
||||
* equivalent to counting the number of
|
||||
* faces incident upon this vertex
|
||||
*/
|
||||
int bmesh_disk_facevert_count(const BMVert *v)
|
||||
{
|
||||
/* is there an edge on this vert at all */
|
||||
@@ -315,14 +302,6 @@ int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief FIND FIRST FACE EDGE
|
||||
*
|
||||
* Finds the first edge in a vertices
|
||||
* Disk cycle that has one of this
|
||||
* vert's loops attached
|
||||
* to it.
|
||||
*/
|
||||
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
|
||||
{
|
||||
const BMEdge *e_iter = e;
|
||||
@@ -334,11 +313,6 @@ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
|
||||
*
|
||||
* The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
|
||||
*/
|
||||
BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
|
||||
{
|
||||
const BMEdge *e_iter = e;
|
||||
@@ -350,9 +324,6 @@ BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #bmesh_disk_faceloop_find_first that ignores hidden faces.
|
||||
*/
|
||||
BMLoop *bmesh_disk_faceloop_find_first_visible(const BMEdge *e, const BMVert *v)
|
||||
{
|
||||
const BMEdge *e_iter = e;
|
||||
@@ -384,7 +355,6 @@ BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v)
|
||||
return (BMEdge *)e;
|
||||
}
|
||||
|
||||
/*****radial cycle functions, e.g. loops surrounding edges**** */
|
||||
bool bmesh_radial_validate(int radlen, BMLoop *l)
|
||||
{
|
||||
BMLoop *l_iter = l;
|
||||
@@ -442,14 +412,6 @@ void bmesh_radial_loop_append(BMEdge *e, BMLoop *l)
|
||||
l->e = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BMESH RADIAL REMOVE LOOP
|
||||
*
|
||||
* Removes a loop from an radial cycle. If edge e is non-NULL
|
||||
* it should contain the radial cycle, and it will also get
|
||||
* updated (in the case that the edge's link into the radial
|
||||
* cycle was the loop which is being removed from the cycle).
|
||||
*/
|
||||
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
|
||||
{
|
||||
/* if e is non-NULL, l must be in the radial cycle of e */
|
||||
@@ -480,10 +442,6 @@ void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
|
||||
l->e = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #bmesh_radial_loop_remove which only performs the radial unlink,
|
||||
* leaving the edge untouched.
|
||||
*/
|
||||
void bmesh_radial_loop_unlink(BMLoop *l)
|
||||
{
|
||||
if (l->radial_next != l) {
|
||||
@@ -497,12 +455,6 @@ void bmesh_radial_loop_unlink(BMLoop *l)
|
||||
l->e = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief BME RADIAL FIND FIRST FACE VERT
|
||||
*
|
||||
* Finds the first loop of v around radial
|
||||
* cycle
|
||||
*/
|
||||
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v)
|
||||
{
|
||||
const BMLoop *l_iter;
|
||||
@@ -553,12 +505,6 @@ int bmesh_radial_length(const BMLoop *l)
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief RADIAL COUNT FACE VERT
|
||||
*
|
||||
* Returns the number of times a vertex appears
|
||||
* in a radial cycle
|
||||
*/
|
||||
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
|
||||
{
|
||||
const BMLoop *l_iter;
|
||||
@@ -590,11 +536,6 @@ int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief RADIAL CHECK FACE VERT
|
||||
*
|
||||
* Quicker check for `bmesh_radial_facevert_count(...) != 0`.
|
||||
*/
|
||||
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
|
||||
{
|
||||
const BMLoop *l_iter;
|
||||
@@ -608,7 +549,6 @@ bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*****loop cycle functions, e.g. loops surrounding a face**** */
|
||||
bool bmesh_loop_validate(BMFace *f)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
*/
|
||||
|
||||
/* LOOP CYCLE MANAGEMENT */
|
||||
/*****loop cycle functions, e.g. loops surrounding a face**** */
|
||||
bool bmesh_loop_validate(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/* DISK CYCLE MANAGEMENT */
|
||||
@@ -48,11 +49,35 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_W
|
||||
ATTR_NONNULL();
|
||||
int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* \brief DISK COUNT FACE VERT
|
||||
*
|
||||
* Counts the number of loop users
|
||||
* for this vertex. Note that this is
|
||||
* equivalent to counting the number of
|
||||
* faces incident upon this vertex
|
||||
*/
|
||||
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
/**
|
||||
* \brief FIND FIRST FACE EDGE
|
||||
*
|
||||
* Finds the first edge in a vertices
|
||||
* Disk cycle that has one of this
|
||||
* vert's loops attached
|
||||
* to it.
|
||||
*/
|
||||
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
|
||||
*
|
||||
* The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
|
||||
*/
|
||||
BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* A version of #bmesh_disk_faceloop_find_first that ignores hidden faces.
|
||||
*/
|
||||
BMLoop *bmesh_disk_faceloop_find_first_visible(const BMEdge *e,
|
||||
const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
@@ -61,7 +86,19 @@ BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WAR
|
||||
|
||||
/* RADIAL CYCLE MANAGEMENT */
|
||||
void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL();
|
||||
/**
|
||||
* \brief BMESH RADIAL REMOVE LOOP
|
||||
*
|
||||
* Removes a loop from an radial cycle. If edge e is non-NULL
|
||||
* it should contain the radial cycle, and it will also get
|
||||
* updated (in the case that the edge's link into the radial
|
||||
* cycle was the loop which is being removed from the cycle).
|
||||
*/
|
||||
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL();
|
||||
/**
|
||||
* A version of #bmesh_radial_loop_remove which only performs the radial unlink,
|
||||
* leaving the edge untouched.
|
||||
*/
|
||||
void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL();
|
||||
/* NOTE:
|
||||
* bmesh_radial_loop_next(BMLoop *l) / prev.
|
||||
@@ -71,20 +108,43 @@ int bmesh_radial_facevert_count_at_most(const BMLoop *l,
|
||||
const BMVert *v,
|
||||
const int count_max) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* \brief RADIAL COUNT FACE VERT
|
||||
*
|
||||
* Returns the number of times a vertex appears
|
||||
* in a radial cycle
|
||||
*/
|
||||
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* \brief RADIAL CHECK FACE VERT
|
||||
*
|
||||
* Quicker check for `bmesh_radial_facevert_count(...) != 0`.
|
||||
*/
|
||||
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/**
|
||||
* \brief BME RADIAL FIND FIRST FACE VERT
|
||||
*
|
||||
* Finds the first loop of v around radial
|
||||
* cycle
|
||||
*/
|
||||
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
BMLoop *bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v) ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_NONNULL();
|
||||
/*****radial cycle functions, e.g. loops surrounding edges**** */
|
||||
bool bmesh_radial_validate(int radlen, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/* EDGE UTILITIES */
|
||||
void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
|
||||
/**
|
||||
* Handles all connected data, use with care.
|
||||
*
|
||||
* Assumes caller has setup correct state before the swap is done.
|
||||
*/
|
||||
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
|
||||
void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
|
||||
BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2) ATTR_WARN_UNUSED_RESULT
|
||||
|
||||
@@ -60,12 +60,6 @@ void *BMW_begin(BMWalker *walker, void *start)
|
||||
return BMW_current_state(walker) ? walker->step(walker) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Init Walker
|
||||
*
|
||||
* Allocates and returns a new mesh walker of a given type.
|
||||
* The elements visited are filtered by the bitmask 'searchmask'.
|
||||
*/
|
||||
void BMW_init(BMWalker *walker,
|
||||
BMesh *bm,
|
||||
int type,
|
||||
@@ -124,11 +118,6 @@ void BMW_init(BMWalker *walker,
|
||||
BLI_listbase_clear(&walker->states);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief End Walker
|
||||
*
|
||||
* Frees a walker's worklist.
|
||||
*/
|
||||
void BMW_end(BMWalker *walker)
|
||||
{
|
||||
BLI_mempool_destroy(walker->worklist);
|
||||
@@ -136,9 +125,6 @@ void BMW_end(BMWalker *walker)
|
||||
BLI_gset_free(walker->visit_set_alt, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Step Walker
|
||||
*/
|
||||
void *BMW_step(BMWalker *walker)
|
||||
{
|
||||
BMHeader *head;
|
||||
@@ -148,22 +134,11 @@ void *BMW_step(BMWalker *walker)
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Walker Current Depth
|
||||
*
|
||||
* Returns the current depth of the walker.
|
||||
*/
|
||||
|
||||
int BMW_current_depth(BMWalker *walker)
|
||||
{
|
||||
return walker->depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Main Walking Function
|
||||
*
|
||||
* Steps a mesh walker forward by one element
|
||||
*/
|
||||
void *BMW_walk(BMWalker *walker)
|
||||
{
|
||||
void *current = NULL;
|
||||
@@ -177,13 +152,6 @@ void *BMW_walk(BMWalker *walker)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Current Walker State
|
||||
*
|
||||
* Returns the first state from the walker state
|
||||
* worklist. This state is the next in the
|
||||
* worklist for processing.
|
||||
*/
|
||||
void *BMW_current_state(BMWalker *walker)
|
||||
{
|
||||
BMwGenericWalker *currentstate = walker->states.first;
|
||||
@@ -203,12 +171,6 @@ void *BMW_current_state(BMWalker *walker)
|
||||
return currentstate;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Remove Current Walker State
|
||||
*
|
||||
* Remove and free an item from the end of the walker state
|
||||
* worklist.
|
||||
*/
|
||||
void BMW_state_remove(BMWalker *walker)
|
||||
{
|
||||
void *oldstate;
|
||||
@@ -217,15 +179,6 @@ void BMW_state_remove(BMWalker *walker)
|
||||
BLI_mempool_free(walker->worklist, oldstate);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add a new Walker State
|
||||
*
|
||||
* Allocate a new empty state and put it on the worklist.
|
||||
* A pointer to the new state is returned so that the caller
|
||||
* can fill in the state data. The new state will be inserted
|
||||
* at the front for depth-first walks, and at the end for
|
||||
* breadth-first walks.
|
||||
*/
|
||||
void *BMW_state_add(BMWalker *walker)
|
||||
{
|
||||
BMwGenericWalker *newstate;
|
||||
@@ -245,12 +198,6 @@ void *BMW_state_add(BMWalker *walker)
|
||||
return newstate;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reset Walker
|
||||
*
|
||||
* Frees all states from the worklist, resetting the walker
|
||||
* for reuse in a new walk.
|
||||
*/
|
||||
void BMW_reset(BMWalker *walker)
|
||||
{
|
||||
while (BMW_current_state(walker)) {
|
||||
|
||||
@@ -67,6 +67,12 @@ typedef struct BMWalker {
|
||||
/* define to make BMW_init more clear */
|
||||
#define BMW_MASK_NOP 0
|
||||
|
||||
/**
|
||||
* \brief Init Walker
|
||||
*
|
||||
* Allocates and returns a new mesh walker of a given type.
|
||||
* The elements visited are filtered by the bitmask 'searchmask'.
|
||||
*/
|
||||
void BMW_init(struct BMWalker *walker,
|
||||
BMesh *bm,
|
||||
int type,
|
||||
@@ -76,15 +82,61 @@ void BMW_init(struct BMWalker *walker,
|
||||
BMWFlag flag,
|
||||
int layer);
|
||||
void *BMW_begin(BMWalker *walker, void *start);
|
||||
/**
|
||||
* \brief Step Walker
|
||||
*/
|
||||
void *BMW_step(struct BMWalker *walker);
|
||||
/**
|
||||
* \brief End Walker
|
||||
*
|
||||
* Frees a walker's worklist.
|
||||
*/
|
||||
void BMW_end(struct BMWalker *walker);
|
||||
/**
|
||||
* \brief Walker Current Depth
|
||||
*
|
||||
* Returns the current depth of the walker.
|
||||
*/
|
||||
int BMW_current_depth(BMWalker *walker);
|
||||
|
||||
/* These are used by custom walkers. */
|
||||
/**
|
||||
* \brief Current Walker State
|
||||
*
|
||||
* Returns the first state from the walker state
|
||||
* worklist. This state is the next in the
|
||||
* worklist for processing.
|
||||
*/
|
||||
void *BMW_current_state(BMWalker *walker);
|
||||
/**
|
||||
* \brief Add a new Walker State
|
||||
*
|
||||
* Allocate a new empty state and put it on the worklist.
|
||||
* A pointer to the new state is returned so that the caller
|
||||
* can fill in the state data. The new state will be inserted
|
||||
* at the front for depth-first walks, and at the end for
|
||||
* breadth-first walks.
|
||||
*/
|
||||
void *BMW_state_add(BMWalker *walker);
|
||||
/**
|
||||
* \brief Remove Current Walker State
|
||||
*
|
||||
* Remove and free an item from the end of the walker state
|
||||
* worklist.
|
||||
*/
|
||||
void BMW_state_remove(BMWalker *walker);
|
||||
/**
|
||||
* \brief Main Walking Function
|
||||
*
|
||||
* Steps a mesh walker forward by one element
|
||||
*/
|
||||
void *BMW_walk(BMWalker *walker);
|
||||
/**
|
||||
* \brief Reset Walker
|
||||
*
|
||||
* Frees all states from the worklist, resetting the walker
|
||||
* for reuse in a new walk.
|
||||
*/
|
||||
void BMW_reset(BMWalker *walker);
|
||||
|
||||
#define BMW_ITER(ele, walker, data) \
|
||||
|
||||
@@ -31,12 +31,11 @@
|
||||
#define ELE_NEW 1
|
||||
#define ELE_OUT 2
|
||||
|
||||
/* This is what runs when pressing the F key
|
||||
* doing the best thing here isn't always easy create vs dissolve, its nice to support
|
||||
* but it _really_ gives issues we might have to not call dissolve. - campbell
|
||||
*/
|
||||
void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
/* NOTE(@campbellbarton): doing the best thing here isn't always easy create vs dissolve,
|
||||
* its nice to support but it _really_ gives issues we might have to not call dissolve. */
|
||||
|
||||
BMOIter oiter;
|
||||
BMHeader *h;
|
||||
int totv = 0, tote = 0, totf = 0;
|
||||
|
||||
@@ -488,7 +488,6 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
|
||||
/* done with cleanup */
|
||||
}
|
||||
|
||||
/* Limited Dissolve */
|
||||
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
BMOpSlot *einput = BMO_slot_get(op->slots_in, "edges");
|
||||
|
||||
@@ -787,14 +787,6 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills first available UV-map with grid-like UV's for all faces with `oflag` set.
|
||||
*
|
||||
* \param bm: The BMesh to operate on
|
||||
* \param x_segments: The x-resolution of the grid
|
||||
* \param y_segments: The y-resolution of the grid
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_grid(BMesh *bm,
|
||||
const uint x_segments,
|
||||
const uint y_segments,
|
||||
@@ -1130,12 +1122,6 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills first available UV-map with spherical projected UVs for all faces with `oflag` set.
|
||||
*
|
||||
* \param bm: The BMesh to operate on
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_offset)
|
||||
{
|
||||
BMFace *f;
|
||||
@@ -1343,14 +1329,6 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
|
||||
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills first available UV-map with 2D projected UVs for all faces with `oflag` set.
|
||||
*
|
||||
* \param bm: The BMesh to operate on.
|
||||
* \param mat: The transform matrix applied to the created circle.
|
||||
* \param radius: The size of the circle.
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_circle(
|
||||
BMesh *bm, float mat[4][4], const float radius, const short oflag, const int cd_loop_uv_offset)
|
||||
{
|
||||
@@ -1534,17 +1512,6 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
|
||||
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills first available UV-map with cylinder/cone-like UVs for all faces with `oflag` set.
|
||||
*
|
||||
* \param bm: The BMesh to operate on.
|
||||
* \param mat: The transform matrix applied to the created cone/cylinder.
|
||||
* \param radius_top: The size of the top end of the cone/cylinder.
|
||||
* \param radius_bottom: The size of the bottom end of the cone/cylinder.
|
||||
* \param segments: The number of subdivisions in the sides of the cone/cylinder.
|
||||
* \param cap_ends: Whether the ends of the cone/cylinder are filled or not.
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_cone(BMesh *bm,
|
||||
float mat[4][4],
|
||||
const float radius_top,
|
||||
@@ -1710,15 +1677,6 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
|
||||
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills first available UV-map with cube-like UVs for all faces with `oflag` set.
|
||||
*
|
||||
* \note Expects tagged faces to be six quads.
|
||||
* \note Caller must order faces for correct alignment.
|
||||
*
|
||||
* \param bm: The BMesh to operate on.
|
||||
* \param oflag: The flag to check faces with.
|
||||
*/
|
||||
void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag)
|
||||
{
|
||||
BMFace *f;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include "intern/bmesh_operators_private.h" /* own include */
|
||||
|
||||
/* keep this operator fast, its used in a modifier */
|
||||
void bmo_split_edges_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts");
|
||||
|
||||
@@ -1061,9 +1061,10 @@ static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v)
|
||||
return BMO_edge_flag_test_bool(bm, e, EDGE_RIM);
|
||||
}
|
||||
|
||||
/* keep this operator fast, its used in a modifier */
|
||||
void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
/* NOTE: keep this operator fast, its used in a modifier. */
|
||||
|
||||
ListBase eloops_rim = {NULL};
|
||||
BMOIter siter;
|
||||
BMEdge *e;
|
||||
|
||||
@@ -29,11 +29,10 @@
|
||||
|
||||
#include "intern/bmesh_operators_private.h" /* own include */
|
||||
|
||||
/* - BMVert.flag & BM_ELEM_TAG: shows we touched this vert
|
||||
* - BMVert.index == -1: shows we will remove this vert
|
||||
*/
|
||||
void bmo_unsubdivide_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
/* - `BMVert.flag & BM_ELEM_TAG`: Shows we touched this vert.
|
||||
* - `BMVert.index == -1`: Shows we will remove this vert. */
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
|
||||
|
||||
@@ -235,12 +235,6 @@ static float bm_edge_calc_rotate_beauty__angle(const float v1[3],
|
||||
return FLT_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming we have 2 triangles sharing an edge (2 - 4),
|
||||
* check if the edge running from (1 - 3) gives better results.
|
||||
*
|
||||
* \return (negative number means the edge can be rotated, lager == better).
|
||||
*/
|
||||
float BM_verts_calc_rotate_beauty(const BMVert *v1,
|
||||
const BMVert *v2,
|
||||
const BMVert *v3,
|
||||
@@ -374,9 +368,6 @@ static void bm_edge_update_beauty_cost(BMEdge *e,
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Beautify Fill */
|
||||
|
||||
/**
|
||||
* \note This function sets the edge indices to invalid values.
|
||||
*/
|
||||
void BM_mesh_beautify_fill(BMesh *bm,
|
||||
BMEdge **edge_array,
|
||||
const int edge_array_len,
|
||||
|
||||
@@ -27,6 +27,9 @@ enum {
|
||||
EDGE_RESTRICT_DEGENERATE = (1 << 1),
|
||||
};
|
||||
|
||||
/**
|
||||
* \note This function sets the edge indices to invalid values.
|
||||
*/
|
||||
void BM_mesh_beautify_fill(BMesh *bm,
|
||||
BMEdge **edge_array,
|
||||
const int edge_array_len,
|
||||
@@ -35,6 +38,12 @@ void BM_mesh_beautify_fill(BMesh *bm,
|
||||
const short oflag_edge,
|
||||
const short oflag_face);
|
||||
|
||||
/**
|
||||
* Assuming we have 2 triangles sharing an edge (2 - 4),
|
||||
* check if the edge running from (1 - 3) gives better results.
|
||||
*
|
||||
* \return (negative number means the edge can be rotated, lager == better).
|
||||
*/
|
||||
float BM_verts_calc_rotate_beauty(const BMVert *v1,
|
||||
const BMVert *v2,
|
||||
const BMVert *v3,
|
||||
|
||||
@@ -7443,18 +7443,6 @@ static void bevel_limit_offset(BevelParams *bp, BMesh *bm)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* - Currently only bevels BM_ELEM_TAG'd verts and edges.
|
||||
*
|
||||
* - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
|
||||
* the caller needs to ensure these are cleared before calling
|
||||
* if its going to use this tag.
|
||||
*
|
||||
* - If limit_offset is set, adjusts offset down if necessary
|
||||
* to avoid geometry collisions.
|
||||
*
|
||||
* \warning all tagged edges _must_ be manifold.
|
||||
*/
|
||||
void BM_mesh_bevel(BMesh *bm,
|
||||
const float offset,
|
||||
const int offset_type,
|
||||
|
||||
@@ -23,6 +23,18 @@
|
||||
struct CurveProfile;
|
||||
struct MDeformVert;
|
||||
|
||||
/**
|
||||
* - Currently only bevels BM_ELEM_TAG'd verts and edges.
|
||||
*
|
||||
* - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
|
||||
* the caller needs to ensure these are cleared before calling
|
||||
* if its going to use this tag.
|
||||
*
|
||||
* - If limit_offset is set, adjusts offset down if necessary
|
||||
* to avoid geometry collisions.
|
||||
*
|
||||
* \warning all tagged edges _must_ be manifold.
|
||||
*/
|
||||
void BM_mesh_bevel(BMesh *bm,
|
||||
const float offset,
|
||||
const int offset_type,
|
||||
|
||||
@@ -411,11 +411,6 @@ finally:
|
||||
/** \name Public BMesh Bisect Function
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \param use_snap_center: Snap verts onto the plane.
|
||||
* \param use_tag: Only bisect tagged edges and faces.
|
||||
* \param oflag_center: Operator flag, enabled for geometry on the axis (existing and created)
|
||||
*/
|
||||
void BM_mesh_bisect_plane(BMesh *bm,
|
||||
const float plane[4],
|
||||
const bool use_snap_center,
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* \param use_snap_center: Snap verts onto the plane.
|
||||
* \param use_tag: Only bisect tagged edges and faces.
|
||||
* \param oflag_center: Operator flag, enabled for geometry on the axis (existing and created)
|
||||
*/
|
||||
void BM_mesh_bisect_plane(BMesh *bm,
|
||||
const float plane[4],
|
||||
const bool use_snap_center,
|
||||
|
||||
@@ -456,14 +456,6 @@ bool BM_mesh_boolean(BMesh *bm,
|
||||
static_cast<blender::meshintersect::BoolOpType>(boolean_mode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a Knife Intersection operation on the mesh bm.
|
||||
* There are either one or two operands, the same as described above for BM_mesh_boolean().
|
||||
* If use_separate_all is true, each edge that is created from the intersection should
|
||||
* be used to separate all its incident faces. TODO: implement that.
|
||||
* TODO: need to ensure that "selected/non-selected" flag of original faces gets propagated
|
||||
* to the intersection result faces.
|
||||
*/
|
||||
bool BM_mesh_boolean_knife(BMesh *bm,
|
||||
struct BMLoop *(*looptris)[3],
|
||||
const int looptris_tot,
|
||||
|
||||
@@ -35,6 +35,16 @@ bool BM_mesh_boolean(BMesh *bm,
|
||||
const bool hole_tolerant,
|
||||
const int boolean_mode);
|
||||
|
||||
/**
|
||||
* Perform a Knife Intersection operation on the mesh `bm`.
|
||||
* There are either one or two operands, the same as described above for #BM_mesh_boolean().
|
||||
*
|
||||
* \param use_separate_all: When true, each edge that is created from the intersection should
|
||||
* be used to separate all its incident faces. TODO: implement that.
|
||||
*
|
||||
* TODO: need to ensure that "selected/non-selected" flag of original faces gets propagated
|
||||
* to the intersection result faces.
|
||||
*/
|
||||
bool BM_mesh_boolean_knife(BMesh *bm,
|
||||
struct BMLoop *(*looptris)[3],
|
||||
const int looptris_tot,
|
||||
|
||||
@@ -20,6 +20,20 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief BM_mesh_decimate
|
||||
* \param bm: The mesh
|
||||
* \param factor: face count multiplier [0 - 1]
|
||||
* \param vweights: Optional array of vertex aligned weights [0 - 1],
|
||||
* a vertex group is the usual source for this.
|
||||
* \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
|
||||
* \param symmetry_eps: Threshold when matching mirror verts.
|
||||
*
|
||||
* \note The caller is responsible for recalculating face and vertex normals.
|
||||
* - Vertex normals are maintained while decimating,
|
||||
* although they won't necessarily match the final recalculated normals.
|
||||
* - Face normals are not maintained at all.
|
||||
*/
|
||||
void BM_mesh_decimate_collapse(BMesh *bm,
|
||||
const float factor,
|
||||
float *vweights,
|
||||
@@ -28,6 +42,8 @@ void BM_mesh_decimate_collapse(BMesh *bm,
|
||||
const int symmetry_axis,
|
||||
const float symmetry_eps);
|
||||
|
||||
/**
|
||||
* \param tag_only: so we can call this from an operator */
|
||||
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only);
|
||||
void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations);
|
||||
|
||||
|
||||
@@ -1277,20 +1277,6 @@ static bool bm_decim_edge_collapse(BMesh *bm,
|
||||
/* Main Decimate Function
|
||||
* ********************** */
|
||||
|
||||
/**
|
||||
* \brief BM_mesh_decimate
|
||||
* \param bm: The mesh
|
||||
* \param factor: face count multiplier [0 - 1]
|
||||
* \param vweights: Optional array of vertex aligned weights [0 - 1],
|
||||
* a vertex group is the usual source for this.
|
||||
* \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
|
||||
* \param symmetry_eps: Threshold when matching mirror verts.
|
||||
*
|
||||
* \note The caller is responsible for recalculating face and vertex normals.
|
||||
* - Vertex normals are maintained while decimating,
|
||||
* although they won't necessarily match the final recalculated normals.
|
||||
* - Face normals are not maintained at all.
|
||||
*/
|
||||
void BM_mesh_decimate_collapse(BMesh *bm,
|
||||
const float factor,
|
||||
float *vweights,
|
||||
|
||||
@@ -168,8 +168,6 @@ enum {
|
||||
* - BMVert.index == -1: shows we will remove this vert
|
||||
*/
|
||||
|
||||
/**
|
||||
* \param tag_only: so we can call this from an operator */
|
||||
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only)
|
||||
{
|
||||
#ifdef USE_WALKER
|
||||
|
||||
@@ -422,15 +422,6 @@ static LinkNode *bm_edgenet_path_calc_best(BMEdge *e,
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in faces from an edgenet made up of boundary and wire edges.
|
||||
*
|
||||
* \note New faces currently don't have their normals calculated and are flipped randomly.
|
||||
* The caller needs to flip faces correctly.
|
||||
*
|
||||
* \param bm: The mesh to operate on.
|
||||
* \param use_edge_tag: Only fill tagged edges.
|
||||
*/
|
||||
void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag)
|
||||
{
|
||||
VertNetInfo *vnet_info = MEM_callocN(sizeof(*vnet_info) * (size_t)bm->totvert, __func__);
|
||||
|
||||
@@ -20,4 +20,13 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fill in faces from an edgenet made up of boundary and wire edges.
|
||||
*
|
||||
* \note New faces currently don't have their normals calculated and are flipped randomly.
|
||||
* The caller needs to flip faces correctly.
|
||||
*
|
||||
* \param bm: The mesh to operate on.
|
||||
* \param use_edge_tag: Only fill tagged edges.
|
||||
*/
|
||||
void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag);
|
||||
|
||||
@@ -28,11 +28,6 @@
|
||||
|
||||
#include "bmesh_edgesplit.h" /* own include */
|
||||
|
||||
/**
|
||||
* \param use_verts: Use flagged verts instead of edges.
|
||||
* \param tag_only: Only split tagged edges.
|
||||
* \param copy_select: Copy selection history.
|
||||
*/
|
||||
void BM_mesh_edgesplit(BMesh *bm,
|
||||
const bool use_verts,
|
||||
const bool tag_only,
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \param use_verts: Use flagged verts instead of edges.
|
||||
* \param tag_only: Only split tagged edges.
|
||||
* \param copy_select: Copy selection history.
|
||||
*/
|
||||
void BM_mesh_edgesplit(BMesh *bm,
|
||||
const bool use_verts,
|
||||
const bool tag_only,
|
||||
|
||||
@@ -947,14 +947,6 @@ static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const f
|
||||
|
||||
#endif /* USE_BVH */
|
||||
|
||||
/**
|
||||
* Intersect tessellated faces
|
||||
* leaving the resulting edges tagged.
|
||||
*
|
||||
* \param test_fn: Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
|
||||
* \param boolean_mode: -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
|
||||
* \return true if the mesh is changed (intersections cut or faces removed from boolean).
|
||||
*/
|
||||
bool BM_mesh_intersect(BMesh *bm,
|
||||
struct BMLoop *(*looptris)[3],
|
||||
const int looptris_tot,
|
||||
|
||||
@@ -24,6 +24,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Intersect tessellated faces
|
||||
* leaving the resulting edges tagged.
|
||||
*
|
||||
* \param test_fn: Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
|
||||
* \param boolean_mode: -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
|
||||
* \return true if the mesh is changed (intersections cut or faces removed from boolean).
|
||||
*/
|
||||
bool BM_mesh_intersect(BMesh *bm,
|
||||
struct BMLoop *(*looptris)[3],
|
||||
const int looptris_tot,
|
||||
|
||||
@@ -1332,12 +1332,6 @@ static void bm_vert_fasthash_destroy(UUIDFashMatch *fm)
|
||||
|
||||
#endif /* USE_PIVOT_FASTMATCH */
|
||||
|
||||
/**
|
||||
* Take a face-region and return a list of matching face-regions.
|
||||
*
|
||||
* \param faces_region: A single, contiguous face-region.
|
||||
* \return A list of matching null-terminated face-region arrays.
|
||||
*/
|
||||
int BM_mesh_region_match(BMesh *bm,
|
||||
BMFace **faces_region,
|
||||
uint faces_region_len,
|
||||
|
||||
@@ -20,6 +20,12 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Take a face-region and return a list of matching face-regions.
|
||||
*
|
||||
* \param faces_region: A single, contiguous face-region.
|
||||
* \return A list of matching null-terminated face-region arrays.
|
||||
*/
|
||||
int BM_mesh_region_match(BMesh *bm,
|
||||
BMFace **faces_region,
|
||||
uint faces_region_len,
|
||||
|
||||
@@ -32,10 +32,6 @@
|
||||
#include "bmesh_separate.h" /* own include */
|
||||
#include "intern/bmesh_private.h"
|
||||
|
||||
/**
|
||||
* Split all faces that match `filter_fn`.
|
||||
* \note
|
||||
*/
|
||||
void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data)
|
||||
{
|
||||
BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__);
|
||||
|
||||
@@ -20,4 +20,8 @@
|
||||
* \ingroup bmesh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Split all faces that match `filter_fn`.
|
||||
* \note
|
||||
*/
|
||||
void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data);
|
||||
|
||||
@@ -152,12 +152,6 @@ static bool bm_loop_is_radial_boundary(BMLoop *l_first)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param defgrp_index: Vertex group index, -1 for no vertex groups.
|
||||
*
|
||||
* \note All edge tags must be cleared.
|
||||
* \note Behavior matches MOD_solidify.c
|
||||
*/
|
||||
void BM_mesh_wireframe(BMesh *bm,
|
||||
const float offset,
|
||||
const float offset_fac,
|
||||
|
||||
@@ -22,6 +22,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \param defgrp_index: Vertex group index, -1 for no vertex groups.
|
||||
*
|
||||
* \note All edge tags must be cleared.
|
||||
* \note Behavior matches MOD_solidify.c
|
||||
*/
|
||||
void BM_mesh_wireframe(BMesh *bm,
|
||||
const float offset,
|
||||
const float offset_fac,
|
||||
|
||||
Reference in New Issue
Block a user