diff options
Diffstat (limited to 'source/blender')
18 files changed, 1007 insertions, 531 deletions
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index 08c0fcc0f3c..856923b7b0f 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -39,10 +39,30 @@ */ struct DerivedMesh; +struct BMEditMesh; struct MVert; struct MFace; /** +* struct that kepts basic information about a BVHTree build from a editmesh +*/ +typedef struct BVHTreeFromEditMesh { + struct BVHTree *tree; + + /* default callbacks to bvh nearest and raycast */ + BVHTree_NearestPointCallback nearest_callback; + BVHTree_RayCastCallback raycast_callback; + BVHTree_NearestToRayCallback nearest_to_ray_callback; + + /* radius for raycast */ + float sphere_radius; + + /* Private data */ + struct BMEditMesh *em; + +} BVHTreeFromEditMesh; + +/** * struct that kepts basic information about a BVHTree build from a mesh */ typedef struct BVHTreeFromMesh { @@ -69,8 +89,6 @@ typedef struct BVHTreeFromMesh { float sphere_radius; /* Private data */ - void *em_evil; - bool em_evil_all; /* ignore selection/hidden state, adding all loops to the tree */ bool cached; } BVHTreeFromMesh; @@ -85,11 +103,19 @@ typedef struct BVHTreeFromMesh { * * free_bvhtree_from_mesh should be called when the tree is no longer needed. */ +BVHTree *bvhtree_from_editmesh_verts( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_editmesh_verts_ex( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + const BLI_bitmap *mask, int verts_num_active, + float epsilon, int tree_type, int axis); + BVHTree *bvhtree_from_mesh_verts( struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); BVHTree *bvhtree_from_mesh_verts_ex( struct BVHTreeFromMesh *data, struct MVert *vert, const int numVerts, - const bool vert_allocated, BLI_bitmap *mask, int numVerts_active, + const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active, float epsilon, int tree_type, int axis); BVHTree *bvhtree_from_mesh_edges( @@ -103,7 +129,15 @@ BVHTree *bvhtree_from_mesh_faces_ex( struct BVHTreeFromMesh *data, struct MVert *vert, const bool vert_allocated, struct MFace *face, const int numFaces, const bool face_allocated, - BLI_bitmap *mask, int numFaces_active, + const BLI_bitmap *mask, int numFaces_active, + float epsilon, int tree_type, int axis); + +BVHTree *bvhtree_from_editmesh_looptri( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, + int tree_type, int axis); +BVHTree *bvhtree_from_editmesh_looptri_ex( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + const BLI_bitmap *mask, int looptri_num_active, float epsilon, int tree_type, int axis); BVHTree *bvhtree_from_mesh_looptri( @@ -113,12 +147,13 @@ BVHTree *bvhtree_from_mesh_looptri_ex( const struct MVert *vert, const bool vert_allocated, const struct MLoop *mloop, const bool loop_allocated, const struct MLoopTri *looptri, const int looptri_num, const bool looptri_allocated, - BLI_bitmap *mask, int looptri_num_active, + const BLI_bitmap *mask, int looptri_num_active, float epsilon, int tree_type, int axis); /** * Frees data allocated by a call to bvhtree_from_mesh_*. */ +void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data); void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data); /** @@ -144,12 +179,6 @@ enum { BVHTREE_FROM_EDGES = 1, BVHTREE_FROM_FACES = 2, BVHTREE_FROM_LOOPTRI = 3, - /* all faces */ - BVHTREE_FROM_FACES_EDITMESH_ALL = 4, - /* visible unselected, only used for transform snapping */ - BVHTREE_FROM_FACES_EDITMESH_SNAP = 5, - // BVHTREE_FROM_EDGES_EDITMESH_SNAP = 6, - BVHTREE_FROM_VERTS_EDITMESH_SNAP = 7, }; typedef struct LinkNode *BVHCache; diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index abba61310a4..5e9c18544b7 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -151,10 +151,10 @@ static void mesh_looptri_nearest_point(void *userdata, int index, const float co } } /* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */ -static void editmesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) +static void editmesh_looptri_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) { - const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata; - BMEditMesh *em = data->em_evil; + const BVHTreeFromEditMesh *data = userdata; + BMEditMesh *em = data->em; const BMLoop **ltri = (const BMLoop **)em->looptris[index]; const float *t0, *t1, *t2; @@ -240,10 +240,10 @@ static void mesh_looptri_spherecast(void *userdata, int index, const BVHTreeRay } } /* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */ -static void editmesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +static void editmesh_looptri_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { - const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata; - BMEditMesh *em = data->em_evil; + const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata; + BMEditMesh *em = data->em; const BMLoop **ltri = (const BMLoop **)em->looptris[index]; const float *t0, *t1, *t2; @@ -296,7 +296,7 @@ static void mesh_edges_nearest_point(void *userdata, int index, const float co[3 /* Helper, does all the point-spherecast work actually. */ static void mesh_verts_spherecast_do( - const BVHTreeFromMesh *UNUSED(data), int index, const float v[3], const BVHTreeRay *ray, BVHTreeRayHit *hit) + int index, const float v[3], const BVHTreeRay *ray, BVHTreeRayHit *hit) { float dist; const float *r1; @@ -314,6 +314,14 @@ static void mesh_verts_spherecast_do( } } +static void editmesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + const BVHTreeFromEditMesh *data = userdata; + BMVert *eve = BM_vert_at_index(data->em->bm, index); + + mesh_verts_spherecast_do(index, eve->co, ray, hit); +} + /* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_verts. * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ static void mesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) @@ -321,7 +329,7 @@ static void mesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *r const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata; const float *v = data->vert[index].co; - mesh_verts_spherecast_do(data, index, v, ray, hit); + mesh_verts_spherecast_do(index, v, ray, hit); } /* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges. @@ -341,7 +349,7 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r /* In case we get a zero-length edge, handle it as a point! */ if (equals_v3v3(v1, v2)) { - mesh_verts_spherecast_do(data, index, v1, ray, hit); + mesh_verts_spherecast_do(index, v1, ray, hit); return; } @@ -380,75 +388,70 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r /** \name Vertex Builder * \{ */ -static BVHTree *bvhtree_from_mesh_verts_create_tree( +static BVHTree *bvhtree_from_editmesh_verts_create_tree( float epsilon, int tree_type, int axis, - BMEditMesh *em, const int *index_array, - MVert *vert, const int numVerts, - BLI_bitmap *mask, int numVerts_active) + BMEditMesh *em, const int verts_num, + const BLI_bitmap *verts_mask, int verts_num_active) { BVHTree *tree = NULL; - BMVert *eve = NULL; int i; - int index = 0; - if (em != NULL) { - BM_mesh_elem_table_ensure(em->bm, BM_VERT); + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + if (verts_mask && verts_num_active == -1) { + verts_num_active = 0; + for (i = 0; i < verts_num; i++) { + if (BLI_BITMAP_TEST_BOOL(verts_mask, i)) { + verts_num_active++; + } + } + } + else if (!verts_mask) { + verts_num_active = verts_num; + } + + tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); + + if (tree) { + BMIter iter; + BMVert *eve; + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { + continue; + } + BLI_bvhtree_insert(tree, i, eve->co, 1); + } + BLI_bvhtree_balance(tree); } + + return tree; +} + +static BVHTree *bvhtree_from_mesh_verts_create_tree( + float epsilon, int tree_type, int axis, + MVert *vert, const int verts_num, + const BLI_bitmap *verts_mask, int verts_num_active) +{ + BVHTree *tree = NULL; + int i; if (vert) { - if (mask && numVerts_active < 0) { - numVerts_active = 0; - for (i = 0; i < numVerts; i++) { - if (BLI_BITMAP_TEST_BOOL(mask, i)) { - if (em != NULL) { - if (index_array) { - index = index_array[i]; - if (index == ORIGINDEX_NONE) { - continue; - } - } - else { - index = i; - } - - eve = BM_vert_at_index(em->bm, index); - if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN) || - BM_elem_flag_test(eve, BM_ELEM_SELECT)) - { - continue; - } - } - numVerts_active++; + if (verts_mask && verts_num_active == -1) { + verts_num_active = 0; + for (i = 0; i < verts_num; i++) { + if (BLI_BITMAP_TEST_BOOL(verts_mask, i)) { + verts_num_active++; } } } - else if (!mask) { - numVerts_active = numVerts; + else if (!verts_mask) { + verts_num_active = verts_num; } - tree = BLI_bvhtree_new(numVerts_active, epsilon, tree_type, axis); + tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); if (tree) { - for (i = 0; i < numVerts; i++) { - if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) { + for (i = 0; i < verts_num; i++) { + if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { continue; } - if (em != NULL) { - if (index_array) { - index = index_array[i]; - if (index == ORIGINDEX_NONE) { - continue; - } - } - else { - index = i; - } - - eve = BM_vert_at_index(em->bm, index); - if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN) || - BM_elem_flag_test(eve, BM_ELEM_SELECT)) - { - continue; - } - } BLI_bvhtree_insert(tree, i, vert[i].co, 1); } @@ -488,17 +491,51 @@ static void bvhtree_from_mesh_verts_setup_data( } } +/* Builds a bvh tree where nodes are the vertices of the given em */ +BVHTree *bvhtree_from_editmesh_verts_ex( + BVHTreeFromEditMesh *data, BMEditMesh *em, + const BLI_bitmap *verts_mask, int verts_num_active, + float epsilon, int tree_type, int axis) +{ + int vert_num = em->bm->totvert; + + BVHTree *tree = bvhtree_from_editmesh_verts_create_tree( + epsilon, tree_type, axis, + em, vert_num, verts_mask, verts_num_active); + + if (tree) { + memset(data, 0, sizeof(*data)); + data->tree = tree; + data->em = em; + data->nearest_callback = NULL; + data->raycast_callback = editmesh_verts_spherecast; + data->nearest_to_ray_callback = NULL; + } + + return tree; +} +BVHTree *bvhtree_from_editmesh_verts( + BVHTreeFromEditMesh *data, BMEditMesh *em, + float epsilon, int tree_type, int axis) +{ + return bvhtree_from_editmesh_verts_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); +} + + /* Builds a bvh tree where nodes are the vertices of the given dm */ -BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) +BVHTree *bvhtree_from_mesh_verts( + BVHTreeFromMesh *data, DerivedMesh *dm, + float epsilon, int tree_type, int axis) { - BMEditMesh *em = data->em_evil; - const int bvhcache_type = em ? BVHTREE_FROM_VERTS_EDITMESH_SNAP : BVHTREE_FROM_VERTS; BVHTree *tree; MVert *vert; bool vert_allocated; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); - tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTS); BLI_rw_mutex_unlock(&cache_rwlock); vert = DM_get_vert_array(dm, &vert_allocated); @@ -506,26 +543,20 @@ BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float e /* Not in cache */ if (tree == NULL) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTS); if (tree == NULL) { - int vert_num, *index_array = NULL; - if (em != NULL) { - vert_num = em->bm->totvert; - index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); - } - else { - vert_num = dm->getNumVerts(dm); - BLI_assert(vert_num != 0); - } + + int vert_num = dm->getNumVerts(dm); + BLI_assert(vert_num != 0); + tree = bvhtree_from_mesh_verts_create_tree( epsilon, tree_type, axis, - em, index_array, vert, vert_num, NULL, -1); if (tree) { /* Save on cache for later use */ /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(&dm->bvhCache, tree, bvhcache_type); + bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS); } } BLI_rw_mutex_unlock(&cache_rwlock); @@ -544,14 +575,15 @@ BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float e * Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!). * \param vert_allocated if true, vert freeing will be done when freeing data. * \param mask if not null, true elements give which vert to add to BVH tree. - * \param numVerts_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask). + * \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_verts_ex( - BVHTreeFromMesh *data, MVert *vert, const int numVerts, const bool vert_allocated, - BLI_bitmap *mask, int numVerts_active, + BVHTreeFromMesh *data, MVert *vert, const int verts_num, const bool vert_allocated, + const BLI_bitmap *verts_mask, int verts_num_active, float epsilon, int tree_type, int axis) { - BVHTree *tree = bvhtree_from_mesh_verts_create_tree(epsilon, tree_type, axis, NULL, NULL, vert, numVerts, mask, numVerts_active); + BVHTree *tree = bvhtree_from_mesh_verts_create_tree( + epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active); /* Setup BVHTreeFromMesh */ bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated); @@ -568,7 +600,9 @@ BVHTree *bvhtree_from_mesh_verts_ex( * \{ */ /* Builds a bvh tree where nodes are the edges of the given dm */ -BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) +BVHTree *bvhtree_from_mesh_edges( + BVHTreeFromMesh *data, DerivedMesh *dm, + float epsilon, int tree_type, int axis) { BVHTree *tree; MVert *vert; @@ -655,107 +689,43 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e static BVHTree *bvhtree_from_mesh_faces_create_tree( float epsilon, int tree_type, int axis, - BMEditMesh *em, const bool em_all, - MVert *vert, MFace *face, const int numFaces, - BLI_bitmap *mask, int numFaces_active) + MVert *vert, MFace *face, const int faces_num, + const BLI_bitmap *faces_mask, int faces_num_active) { BVHTree *tree = NULL; int i; - if (numFaces) { - if (mask && numFaces_active < 0) { - numFaces_active = 0; - for (i = 0; i < numFaces; i++) { - if (BLI_BITMAP_TEST_BOOL(mask, i)) { - numFaces_active++; + if (faces_num) { + if (faces_mask && faces_num_active == -1) { + faces_num_active = 0; + for (i = 0; i < faces_num; i++) { + if (BLI_BITMAP_TEST_BOOL(faces_mask, i)) { + faces_num_active++; } } } - else if (!mask) { - numFaces_active = numFaces; + else if (!faces_mask) { + faces_num_active = faces_num; } /* Create a bvh-tree of the given target */ /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */ - tree = BLI_bvhtree_new(numFaces_active, epsilon, tree_type, axis); + tree = BLI_bvhtree_new(faces_num_active, epsilon, tree_type, axis); if (tree) { - if (em) { - const struct BMLoop *(*looptris)[3] = (void *)em->looptris; - - /* avoid double-up on face searches for quads-ngons */ - bool insert_prev = false; - BMFace *f_prev = NULL; - - /* data->em_evil is only set for snapping, and only for the mesh of the object - * which is currently open in edit mode. When set, the bvhtree should not contain - * faces that will interfere with snapping (e.g. faces that are hidden/selected - * or faces that have selected verts). */ - - /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden - * and/or selected. Even if the faces themselves are not selected for the snapped - * transform, having a vertex selected means the face (and thus it's tessellated - * triangles) will be moving and will not be a good snap targets. */ - for (i = 0; i < numFaces; i++) { - const BMLoop **ltri = looptris[i]; - BMFace *f = ltri[0]->f; - bool insert = mask ? BLI_BITMAP_TEST_BOOL(mask, i) : true; - - /* Start with the assumption the triangle should be included for snapping. */ - if (f == f_prev) { - insert = insert_prev; - } - else if (insert) { - if (em_all) { - /* pass */ - } - else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - /* Don't insert triangles tessellated from faces that are hidden or selected */ - insert = false; - } - else { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) { - /* Don't insert triangles tessellated from faces that have any selected verts */ - insert = false; - break; - } - } while ((l_iter = l_iter->next) != l_first); - } - - /* skip if face doesn't change */ - f_prev = f; - insert_prev = insert; + if (vert && face) { + for (i = 0; i < faces_num; i++) { + float co[4][3]; + if (faces_mask && !BLI_BITMAP_TEST_BOOL(faces_mask, i)) { + continue; } - if (insert) { - /* No reason found to block hit-testing the triangle for snap, so insert it now.*/ - float co[3][3]; - copy_v3_v3(co[0], ltri[0]->v->co); - copy_v3_v3(co[1], ltri[1]->v->co); - copy_v3_v3(co[2], ltri[2]->v->co); + copy_v3_v3(co[0], vert[face[i].v1].co); + copy_v3_v3(co[1], vert[face[i].v2].co); + copy_v3_v3(co[2], vert[face[i].v3].co); + if (face[i].v4) + copy_v3_v3(co[3], vert[face[i].v4].co); - BLI_bvhtree_insert(tree, i, co[0], 3); - } - } - } - else { - if (vert && face) { - for (i = 0; i < numFaces; i++) { - float co[4][3]; - if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) { - continue; - } - - copy_v3_v3(co[0], vert[face[i].v1].co); - copy_v3_v3(co[1], vert[face[i].v2].co); - copy_v3_v3(co[2], vert[face[i].v3].co); - if (face[i].v4) - copy_v3_v3(co[3], vert[face[i].v4].co); - - BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); - } + BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); } } BLI_bvhtree_balance(tree); @@ -766,33 +736,24 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree( } static void bvhtree_from_mesh_faces_setup_data( - BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, - float epsilon, BMEditMesh *em, + BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon, MVert *vert, const bool vert_allocated, MFace *face, const bool face_allocated) { memset(data, 0, sizeof(*data)); - data->em_evil = em; if (tree) { data->tree = tree; data->cached = is_cached; - if (em) { - data->nearest_callback = editmesh_faces_nearest_point; - data->raycast_callback = editmesh_faces_spherecast; - data->nearest_to_ray_callback = NULL; - } - else { - data->nearest_callback = mesh_faces_nearest_point; - data->raycast_callback = mesh_faces_spherecast; - data->nearest_to_ray_callback = NULL; - - data->vert = vert; - data->vert_allocated = vert_allocated; - data->face = face; - data->face_allocated = face_allocated; - } + data->nearest_callback = mesh_faces_nearest_point; + data->raycast_callback = mesh_faces_spherecast; + data->nearest_to_ray_callback = NULL; + + data->vert = vert; + data->vert_allocated = vert_allocated; + data->face = face; + data->face_allocated = face_allocated; data->sphere_radius = epsilon; } @@ -807,54 +768,37 @@ static void bvhtree_from_mesh_faces_setup_data( } /* Builds a bvh tree where nodes are the tesselated faces of the given dm */ -BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) +BVHTree *bvhtree_from_mesh_faces( + BVHTreeFromMesh *data, DerivedMesh *dm, + float epsilon, int tree_type, int axis) { - BMEditMesh *em = data->em_evil; - const int bvhcache_type = em ? - (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) : - BVHTREE_FROM_FACES; BVHTree *tree; MVert *vert = NULL; MFace *face = NULL; bool vert_allocated = false, face_allocated = false; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); - tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_FACES); BLI_rw_mutex_unlock(&cache_rwlock); - if (em == NULL) { - vert = DM_get_vert_array(dm, &vert_allocated); - face = DM_get_tessface_array(dm, &face_allocated); - } + vert = DM_get_vert_array(dm, &vert_allocated); + face = DM_get_tessface_array(dm, &face_allocated); /* Not in cache */ if (tree == NULL) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_FACES); if (tree == NULL) { - int numFaces; - - /* BMESH specific check that we have tessfaces, - * we _could_ tessellate here but rather not - campbell - * - * this assert checks we have tessfaces, - * if not caller should use DM_ensure_tessface() */ - if (em) { - numFaces = em->tottri; - } - else { - numFaces = dm->getNumTessFaces(dm); - BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0)); - } + int numFaces = dm->getNumTessFaces(dm); + BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0)); tree = bvhtree_from_mesh_faces_create_tree( epsilon, tree_type, axis, - em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL), vert, face, numFaces, NULL, -1); if (tree) { /* Save on cache for later use */ /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(&dm->bvhCache, tree, bvhcache_type); + bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_FACES); } } BLI_rw_mutex_unlock(&cache_rwlock); @@ -864,7 +808,7 @@ BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float e } /* Setup BVHTreeFromMesh */ - bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, em, vert, vert_allocated, face, face_allocated); + bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, vert, vert_allocated, face, face_allocated); return data->tree; } @@ -879,16 +823,16 @@ BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float e BVHTree *bvhtree_from_mesh_faces_ex( BVHTreeFromMesh *data, MVert *vert, const bool vert_allocated, MFace *face, const int numFaces, const bool face_allocated, - BLI_bitmap *mask, int numFaces_active, float epsilon, int tree_type, int axis) + const BLI_bitmap *faces_mask, int faces_num_active, + float epsilon, int tree_type, int axis) { BVHTree *tree = bvhtree_from_mesh_faces_create_tree( epsilon, tree_type, axis, - NULL, false, vert, face, numFaces, - mask, numFaces_active); + faces_mask, faces_num_active); /* Setup BVHTreeFromMesh */ - bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, NULL, vert, vert_allocated, face, face_allocated); + bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, vert, vert_allocated, face, face_allocated); return data->tree; } @@ -901,25 +845,24 @@ BVHTree *bvhtree_from_mesh_faces_ex( /** \name LoopTri Face Builder * \{ */ -static BVHTree *bvhtree_from_mesh_looptri_create_tree( +static BVHTree *bvhtree_from_editmesh_looptri_create_tree( float epsilon, int tree_type, int axis, - BMEditMesh *em, const bool em_all, - const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num, - BLI_bitmap *mask, int looptri_num_active) + BMEditMesh *em, const int looptri_num, + const BLI_bitmap *looptri_mask, int looptri_num_active) { BVHTree *tree = NULL; int i; if (looptri_num) { - if (mask && looptri_num_active < 0) { + if (looptri_mask && looptri_num_active == -1) { looptri_num_active = 0; for (i = 0; i < looptri_num; i++) { - if (BLI_BITMAP_TEST_BOOL(mask, i)) { + if (BLI_BITMAP_TEST_BOOL(looptri_mask, i)) { looptri_num_active++; } } } - else if (!mask) { + else if (!looptri_mask) { looptri_num_active = looptri_num; } @@ -930,52 +873,13 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree( if (em) { const struct BMLoop *(*looptris)[3] = (void *)em->looptris; - /* avoid double-up on face searches for quads-ngons */ - bool insert_prev = false; - BMFace *f_prev = NULL; - - /* data->em_evil is only set for snapping, and only for the mesh of the object - * which is currently open in edit mode. When set, the bvhtree should not contain - * faces that will interfere with snapping (e.g. faces that are hidden/selected - * or faces that have selected verts). */ - /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden * and/or selected. Even if the faces themselves are not selected for the snapped * transform, having a vertex selected means the face (and thus it's tessellated * triangles) will be moving and will not be a good snap targets. */ for (i = 0; i < looptri_num; i++) { const BMLoop **ltri = looptris[i]; - BMFace *f = ltri[0]->f; - bool insert = mask ? BLI_BITMAP_TEST_BOOL(mask, i) : true; - - /* Start with the assumption the triangle should be included for snapping. */ - if (f == f_prev) { - insert = insert_prev; - } - else if (insert) { - if (em_all) { - /* pass */ - } - else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - /* Don't insert triangles tessellated from faces that are hidden or selected */ - insert = false; - } - else { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) { - /* Don't insert triangles tessellated from faces that have any selected verts */ - insert = false; - break; - } - } while ((l_iter = l_iter->next) != l_first); - } - - /* skip if face doesn't change */ - f_prev = f; - insert_prev = insert; - } + bool insert = looptri_mask ? BLI_BITMAP_TEST_BOOL(looptri_mask, i) : true; if (insert) { /* No reason found to block hit-testing the triangle for snap, so insert it now.*/ @@ -988,20 +892,50 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree( } } } - else { - if (vert && looptri) { - for (i = 0; i < looptri_num; i++) { - float co[3][3]; - if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) { - continue; - } + BLI_bvhtree_balance(tree); + } + } - copy_v3_v3(co[0], vert[mloop[looptri[i].tri[0]].v].co); - copy_v3_v3(co[1], vert[mloop[looptri[i].tri[1]].v].co); - copy_v3_v3(co[2], vert[mloop[looptri[i].tri[2]].v].co); + return tree; +} - BLI_bvhtree_insert(tree, i, co[0], 3); +static BVHTree *bvhtree_from_mesh_looptri_create_tree( + float epsilon, int tree_type, int axis, + const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num, + const BLI_bitmap *looptri_mask, int looptri_num_active) +{ + BVHTree *tree = NULL; + int i; + + if (looptri_num) { + if (looptri_mask && looptri_num_active == -1) { + looptri_num_active = 0; + for (i = 0; i < looptri_num; i++) { + if (BLI_BITMAP_TEST_BOOL(looptri_mask, i)) { + looptri_num_active++; + } + } + } + else if (!looptri_mask) { + looptri_num_active = looptri_num; + } + + /* Create a bvh-tree of the given target */ + /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */ + tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis); + if (tree) { + if (vert && looptri) { + for (i = 0; i < looptri_num; i++) { + float co[3][3]; + if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) { + continue; } + + copy_v3_v3(co[0], vert[mloop[looptri[i].tri[0]].v].co); + copy_v3_v3(co[1], vert[mloop[looptri[i].tri[1]].v].co); + copy_v3_v3(co[2], vert[mloop[looptri[i].tri[2]].v].co); + + BLI_bvhtree_insert(tree, i, co[0], 3); } } BLI_bvhtree_balance(tree); @@ -1012,36 +946,27 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree( } static void bvhtree_from_mesh_looptri_setup_data( - BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, - float epsilon, BMEditMesh *em, + BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon, const MVert *vert, const bool vert_allocated, const MLoop *mloop, const bool loop_allocated, const MLoopTri *looptri, const bool looptri_allocated) { memset(data, 0, sizeof(*data)); - data->em_evil = em; if (tree) { data->tree = tree; data->cached = is_cached; - if (em) { - data->nearest_callback = editmesh_faces_nearest_point; - data->raycast_callback = editmesh_faces_spherecast; - data->nearest_to_ray_callback = NULL; - } - else { - data->nearest_callback = mesh_looptri_nearest_point; - data->raycast_callback = mesh_looptri_spherecast; - data->nearest_to_ray_callback = NULL; - - data->vert = vert; - data->vert_allocated = vert_allocated; - data->loop = mloop; - data->loop_allocated = loop_allocated; - data->looptri = looptri; - data->looptri_allocated = looptri_allocated; - } + data->nearest_callback = mesh_looptri_nearest_point; + data->raycast_callback = mesh_looptri_spherecast; + data->nearest_to_ray_callback = NULL; + + data->vert = vert; + data->vert_allocated = vert_allocated; + data->loop = mloop; + data->loop_allocated = loop_allocated; + data->looptri = looptri; + data->looptri_allocated = looptri_allocated; data->sphere_radius = epsilon; } @@ -1059,16 +984,52 @@ static void bvhtree_from_mesh_looptri_setup_data( } /** + * Builds a bvh tree where nodes are the looptri faces of the given bm + */ +BVHTree *bvhtree_from_editmesh_looptri_ex( + BVHTreeFromEditMesh *data, BMEditMesh *em, + const BLI_bitmap *looptri_mask, int looptri_num_active, + float epsilon, int tree_type, int axis) +{ + /* BMESH specific check that we have tessfaces, + * we _could_ tessellate here but rather not - campbell + * + * this assert checks we have tessfaces, + * if not caller should use DM_ensure_tessface() */ + + BVHTree *tree = bvhtree_from_editmesh_looptri_create_tree( + epsilon, tree_type, axis, + em, em->tottri, looptri_mask, looptri_num_active); + + if (tree) { + data->tree = tree; + data->nearest_callback = editmesh_looptri_nearest_point; + data->raycast_callback = editmesh_looptri_spherecast; + data->nearest_to_ray_callback = NULL; + data->sphere_radius = 0.0f; + data->em = em; + } + return tree; +} + +BVHTree *bvhtree_from_editmesh_looptri( + BVHTreeFromEditMesh *data, BMEditMesh *em, + float epsilon, int tree_type, int axis) +{ + return bvhtree_from_editmesh_looptri_ex( + data, em, NULL, -1, + epsilon, tree_type, axis); +} + +/** * Builds a bvh tree where nodes are the looptri faces of the given dm * * \note for editmesh this is currently a duplicate of bvhtree_from_mesh_faces */ -BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) +BVHTree *bvhtree_from_mesh_looptri( + BVHTreeFromMesh *data, DerivedMesh *dm, + float epsilon, int tree_type, int axis) { - BMEditMesh *em = data->em_evil; - const int bvhcache_type = em ? - (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) : - BVHTREE_FROM_LOOPTRI; BVHTree *tree; MVert *mvert = NULL; MLoop *mloop = NULL; @@ -1078,58 +1039,42 @@ BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float bool looptri_allocated = false; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); - tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_LOOPTRI); BLI_rw_mutex_unlock(&cache_rwlock); - if (em == NULL) { - MPoly *mpoly; - bool poly_allocated = false; + MPoly *mpoly; + bool poly_allocated = false; - mvert = DM_get_vert_array(dm, &vert_allocated); - mpoly = DM_get_poly_array(dm, &poly_allocated); + mvert = DM_get_vert_array(dm, &vert_allocated); + mpoly = DM_get_poly_array(dm, &poly_allocated); - mloop = DM_get_loop_array(dm, &loop_allocated); - looptri = DM_get_looptri_array( - dm, - mvert, - mpoly, dm->getNumPolys(dm), - mloop, dm->getNumLoops(dm), - &looptri_allocated); - - if (poly_allocated) { - MEM_freeN(mpoly); - } + mloop = DM_get_loop_array(dm, &loop_allocated); + looptri = DM_get_looptri_array( + dm, + mvert, + mpoly, dm->getNumPolys(dm), + mloop, dm->getNumLoops(dm), + &looptri_allocated); + if (poly_allocated) { + MEM_freeN(mpoly); } /* Not in cache */ if (tree == NULL) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_LOOPTRI); if (tree == NULL) { - int looptri_num; - - /* BMESH specific check that we have tessfaces, - * we _could_ tessellate here but rather not - campbell - * - * this assert checks we have tessfaces, - * if not caller should use DM_ensure_tessface() */ - if (em) { - looptri_num = em->tottri; - } - else { - looptri_num = dm->getNumLoopTri(dm); - BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0)); - } + int looptri_num = dm->getNumLoopTri(dm); + BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0)); tree = bvhtree_from_mesh_looptri_create_tree( epsilon, tree_type, axis, - em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL), mvert, mloop, looptri, looptri_num, NULL, -1); if (tree) { /* Save on cache for later use */ /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(&dm->bvhCache, tree, bvhcache_type); + bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_LOOPTRI); } } BLI_rw_mutex_unlock(&cache_rwlock); @@ -1140,7 +1085,7 @@ BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float /* Setup BVHTreeFromMesh */ bvhtree_from_mesh_looptri_setup_data( - data, tree, true, epsilon, em, + data, tree, true, epsilon, mvert, vert_allocated, mloop, loop_allocated, looptri, looptri_allocated); @@ -1153,18 +1098,17 @@ BVHTree *bvhtree_from_mesh_looptri_ex( const struct MVert *vert, const bool vert_allocated, const struct MLoop *mloop, const bool loop_allocated, const struct MLoopTri *looptri, const int looptri_num, const bool looptri_allocated, - BLI_bitmap *mask, int looptri_num_active, + const BLI_bitmap *looptri_mask, int looptri_num_active, float epsilon, int tree_type, int axis) { BVHTree *tree = bvhtree_from_mesh_looptri_create_tree( epsilon, tree_type, axis, - NULL, false, vert, mloop, looptri, looptri_num, - mask, looptri_num_active); + looptri_mask, looptri_num_active); /* Setup BVHTreeFromMesh */ bvhtree_from_mesh_looptri_setup_data( - data, tree, false, epsilon, NULL, + data, tree, false, epsilon, vert, vert_allocated, mloop, loop_allocated, looptri, looptri_allocated); @@ -1175,6 +1119,15 @@ BVHTree *bvhtree_from_mesh_looptri_ex( /** \} */ +/* Frees data allocated by a call to bvhtree_from_editmesh_*. */ +void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data) +{ + if (data->tree) { + BLI_bvhtree_free(data->tree); + memset(data, 0, sizeof(*data)); + } +} + /* Frees data allocated by a call to bvhtree_from_mesh_*. */ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data) { diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index badf78edfb1..e855f6faa22 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -245,11 +245,11 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for * for finding the best hit, to get the real dist, * measure the len_v3v3() from the input coord to hit.co */ BVHTreeRayHit hit; - BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; + void *treeData = NULL; /* auxiliary target */ DerivedMesh *auxMesh = NULL; - BVHTreeFromMesh auxData = NULL_BVHTreeFromMesh; + void *auxData = NULL; SpaceTransform local2aux; /* If the user doesn't allows to project in any direction of projection axis @@ -285,19 +285,44 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for } /* use editmesh to avoid array allocation */ + BMEditMesh *emtarget = NULL, *emaux = NULL; + BVHTreeFromEditMesh emtreedata_stack, emauxdata_stack; + BVHTreeFromMesh dmtreedata_stack, dmauxdata_stack; + BVHTree *targ_tree; + void *targ_callback; if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) { - treeData.em_evil = BKE_editmesh_from_object(calc->smd->target); - treeData.em_evil_all = true; + emtarget = BKE_editmesh_from_object(calc->smd->target); + if ((targ_tree = bvhtree_from_editmesh_looptri(&emtreedata_stack, emtarget, 0.0, 4, 6))) { + targ_callback = emtreedata_stack.raycast_callback; + treeData = &emtreedata_stack; + } } - if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) { - auxData.em_evil = BKE_editmesh_from_object(calc->smd->auxTarget); - auxData.em_evil_all = true; + else { + if ((targ_tree = bvhtree_from_mesh_looptri(&dmtreedata_stack, calc->target, 0.0, 4, 6))) { + targ_callback = dmtreedata_stack.raycast_callback; + treeData = &dmtreedata_stack; + } } - - /* After sucessufuly build the trees, start projection vertexs */ - if (bvhtree_from_mesh_looptri(&treeData, calc->target, 0.0, 4, 6) && - (auxMesh == NULL || bvhtree_from_mesh_looptri(&auxData, auxMesh, 0.0, 4, 6))) - { + if (targ_tree) { + BVHTree *aux_tree = NULL; + void *aux_callback; + if (auxMesh != NULL) { + /* use editmesh to avoid array allocation */ + if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) { + emaux = BKE_editmesh_from_object(calc->smd->auxTarget); + if ((aux_tree = bvhtree_from_editmesh_looptri(&emauxdata_stack, emaux, 0.0, 4, 6)) != NULL) { + aux_callback = emauxdata_stack.raycast_callback; + auxData = &emauxdata_stack; + } + } + else { + if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, calc->target, 0.0, 4, 6)) != NULL) { + aux_callback = dmauxdata_stack.raycast_callback; + auxData = &dmauxdata_stack; + } + } + } + /* After sucessufuly build the trees, start projection vertexs */ #ifndef __APPLE__ #pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT) @@ -340,15 +365,17 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for /* Project over positive direction of axis */ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { - if (auxData.tree) { - BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no, - &local2aux, auxData.tree, &hit, - auxData.raycast_callback, &auxData); + if (aux_tree) { + BKE_shrinkwrap_project_normal( + 0, tmp_co, tmp_no, + &local2aux, aux_tree, &hit, + aux_callback, auxData); } - BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, tmp_no, - &calc->local2target, treeData.tree, &hit, - treeData.raycast_callback, &treeData); + BKE_shrinkwrap_project_normal( + calc->smd->shrinkOpts, tmp_co, tmp_no, + &calc->local2target, targ_tree, &hit, + targ_callback, treeData); } /* Project over negative direction of axis */ @@ -356,15 +383,17 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for float inv_no[3]; negate_v3_v3(inv_no, tmp_no); - if (auxData.tree) { - BKE_shrinkwrap_project_normal(0, tmp_co, inv_no, - &local2aux, auxData.tree, &hit, - auxData.raycast_callback, &auxData); + if (aux_tree) { + BKE_shrinkwrap_project_normal( + 0, tmp_co, inv_no, + &local2aux, aux_tree, &hit, + aux_callback, auxData); } - BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, inv_no, - &calc->local2target, treeData.tree, &hit, - treeData.raycast_callback, &treeData); + BKE_shrinkwrap_project_normal( + calc->smd->shrinkOpts, tmp_co, inv_no, + &calc->local2target, targ_tree, &hit, + targ_callback, treeData); } /* don't set the initial dist (which is more efficient), @@ -383,8 +412,14 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for } /* free data structures */ - free_bvhtree_from_mesh(&treeData); - free_bvhtree_from_mesh(&auxData); + if (treeData) { + if (emtarget) free_bvhtree_from_editmesh(treeData); + else free_bvhtree_from_mesh(treeData); + } + if (auxData) { + if (emaux) free_bvhtree_from_editmesh(auxData); + else free_bvhtree_from_mesh(auxData); + } } /* diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 7ab2b784812..fcd35de0bb3 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -33,7 +33,6 @@ #include <float.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> #ifdef __SSE2__ # include <emmintrin.h> diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c index 4014d29966a..1ee629d203b 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.c +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -31,6 +31,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_bitmap.h" #include "bmesh.h" #include "intern/bmesh_private.h" @@ -250,6 +251,55 @@ void *BMO_iter_as_arrayN( } } +int BM_iter_mesh_bitmap_from_filter( + const char itype, BMesh *bm, + BLI_bitmap *bitmap, + bool (*test_fn)(BMElem *, void *user_data), + void *user_data) +{ + BMIter iter; + BMElem *ele; + int i; + + BM_ITER_MESH_INDEX (ele, &iter, bm, itype, i) { + BLI_BITMAP_SET(bitmap, i, test_fn(ele, user_data)); + } + + return i; +} + +/** + * 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), + void *user_data) +{ + BMIter iter; + BMFace *f; + int i; + int j = 0; + + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { + if (test_fn(f, user_data)) { + for (int A = 2; A < f->len; A++) { + BLI_BITMAP_ENABLE(bitmap, j); + j++; + } + } + else { + for (int A = 2; A < f->len; A++) { + BLI_BITMAP_DISABLE(bitmap, j); + j++; + } + } + } + + return j; +} + /** * \brief Elem Iter Flag Count * diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h index 336e9d88dea..0551d824131 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.h +++ b/source/blender/bmesh/intern/bmesh_iterators.h @@ -208,6 +208,18 @@ void *BMO_iter_as_arrayN( int *r_len, /* optional args to avoid an alloc (normally stack array) */ void **stack_array, int stack_array_size); + +int BM_iter_mesh_bitmap_from_filter( + const char itype, BMesh *bm, + unsigned int *bitmap, + bool (*test_fn)(BMElem *, void *user_data), + void *user_data); +int BM_iter_mesh_bitmap_from_filter_tessface( + BMesh *bm, + unsigned int *bitmap, + bool (*test_fn)(BMFace *, void *user_data), + void *user_data); + int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value); int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data, const short oflag, const bool value); int BM_iter_mesh_count(const char itype, BMesh *bm); diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index b62714700fa..7401a213496 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -47,6 +47,7 @@ #include "BIF_generate.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index aedfbd4f774..91927fbc793 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -64,6 +64,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "ED_types.h" #include "ED_util.h" #include "ED_view3d.h" diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 39df52e5f68..c881e849cf5 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -201,67 +201,4 @@ bool snapNodesContext( /* return args */ float r_loc[2], float *r_dist_px, char *r_node_border); - -/* transform_snap_object.c */ - -/* ED_transform_snap_object_*** API */ -struct SnapObjectParams { - SnapSelect snap_select; - union { - unsigned int snap_to : 4; - /* snap_target_flag: Snap to vert/edge/face. */ - unsigned int snap_to_flag : 4; - }; - /* use editmode cage */ - unsigned int use_object_edit : 1; - /* special context sensitive handling for the active object */ - unsigned int use_object_active : 1; -}; - -enum { - SNAP_OBJECT_USE_CACHE = (1 << 0), -}; - -typedef struct SnapObjectContext SnapObjectContext; -SnapObjectContext *ED_transform_snap_object_context_create( - struct Main *bmain, struct Scene *scene, int flag); -SnapObjectContext *ED_transform_snap_object_context_create_view3d( - struct Main *bmain, struct Scene *scene, int flag, - /* extra args for view3d */ - struct ARegion *ar, struct View3D *v3d); -void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); - -bool ED_transform_snap_object_project_ray_ex( - struct SnapObjectContext *sctx, - const struct SnapObjectParams *params, - const float ray_start[3], const float ray_normal[3], float *ray_depth, - /* return args */ - float r_loc[3], float r_no[3], int *r_index, - struct Object **r_ob, float r_obmat[4][4]); -bool ED_transform_snap_object_project_ray( - SnapObjectContext *sctx, - const float ray_origin[3], const float ray_direction[3], float *ray_dist, - float r_co[3], float r_no[3]); - -bool ED_transform_snap_object_project_view3d_ex( - struct SnapObjectContext *sctx, - const struct SnapObjectParams *params, - const float mval[2], float *dist_px, - float *ray_depth, - float r_loc[3], float r_no[3], int *r_index); -bool ED_transform_snap_object_project_view3d( - struct SnapObjectContext *sctx, - const struct SnapObjectParams *params, - const float mval[2], float *dist_px, - float *ray_depth, - /* return args */ - float r_loc[3], float r_no[3]); -bool ED_transform_snap_object_project_view3d_mixed( - SnapObjectContext *sctx, - const struct SnapObjectParams *params, - const float mval_fl[2], float *dist_px, - bool use_depth, - float r_co[3], float r_no[3]); - - #endif /* __ED_TRANSFORM_H__ */ diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h new file mode 100644 index 00000000000..e591a91a90f --- /dev/null +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -0,0 +1,107 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ED_transform_snap_object_context.h + * \ingroup editors + */ + +#ifndef __ED_TRANSFORM_SNAP_OBJECT_CONTEXT_H__ +#define __ED_TRANSFORM_SNAP_OBJECT_CONTEXT_H__ + +struct BMVert; +struct BMEdge; +struct BMFace; + +struct Scene; +struct Main; +struct Object; +struct ARegion; +struct View3D; + +/* transform_snap_object.c */ + +/* ED_transform_snap_object_*** API */ +struct SnapObjectParams { + int snap_select; /* SnapSelect */ + union { + unsigned int snap_to : 4; + /* snap_target_flag: Snap to vert/edge/face. */ + unsigned int snap_to_flag : 4; + }; + /* use editmode cage */ + unsigned int use_object_edit : 1; + /* special context sensitive handling for the active object */ + unsigned int use_object_active : 1; +}; + +enum { + SNAP_OBJECT_USE_CACHE = (1 << 0), +}; + +typedef struct SnapObjectContext SnapObjectContext; +SnapObjectContext *ED_transform_snap_object_context_create( + struct Main *bmain, struct Scene *scene, int flag); +SnapObjectContext *ED_transform_snap_object_context_create_view3d( + struct Main *bmain, struct Scene *scene, int flag, + /* extra args for view3d */ + struct ARegion *ar, struct View3D *v3d); +void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); + +/* callbacks to filter how snap works */ +void ED_transform_snap_object_context_set_editmesh_callbacks( + SnapObjectContext *sctx, + bool (*test_vert_fn)(struct BMVert *, void *user_data), + bool (*test_edge_fn)(struct BMEdge *, void *user_data), + bool (*test_face_fn)(struct BMFace *, void *user_data), + void *user_data); + +bool ED_transform_snap_object_project_ray_ex( + struct SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], int *r_index, + struct Object **r_ob, float r_obmat[4][4]); +bool ED_transform_snap_object_project_ray( + SnapObjectContext *sctx, + const float ray_origin[3], const float ray_direction[3], float *ray_dist, + float r_co[3], float r_no[3]); + +bool ED_transform_snap_object_project_view3d_ex( + struct SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], float *dist_px, + float *ray_depth, + float r_loc[3], float r_no[3], int *r_index); +bool ED_transform_snap_object_project_view3d( + struct SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval[2], float *dist_px, + float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3]); +bool ED_transform_snap_object_project_view3d_mixed( + SnapObjectContext *sctx, + const struct SnapObjectParams *params, + const float mval_fl[2], float *dist_px, + bool use_depth, + float r_co[3], float r_no[3]); + +#endif /* __ED_TRANSFORM_SNAP_OBJECT_CONTEXT_H__ */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 49794d2e5cd..dc8e7bbb545 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -68,6 +68,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "ED_uvedit.h" #include "ED_view3d.h" diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 26eb707624a..6789970d00f 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -47,6 +47,7 @@ #include "ED_screen.h" #include "ED_view3d.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "ED_space_api.h" #include "BLF_api.h" diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 73ec0f664da..47f81678699 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -49,7 +49,7 @@ #include "ED_screen.h" #include "ED_space_api.h" -#include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "PIL_time.h" /* smoothview */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 5858210cd4f..11151a9c65a 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -59,6 +59,7 @@ struct wmTimer; struct ARegion; struct ReportList; struct EditBone; +struct SnapObjectContext; /* transinfo->redraw */ typedef enum { @@ -105,7 +106,7 @@ typedef struct TransSnap { /** * Re-usable snap context data. */ - SnapObjectContext *object_context; + struct SnapObjectContext *object_context; } TransSnap; typedef struct TransCon { diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 9e8454bf6fb..24b4b16e13f 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -68,6 +68,7 @@ #include "ED_node.h" #include "ED_uvedit.h" #include "ED_view3d.h" +#include "ED_transform_snap_object_context.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -571,6 +572,13 @@ static void initSnappingMode(TransInfo *t) t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( G.main, t->scene, SNAP_OBJECT_USE_CACHE, t->ar, t->view); + + ED_transform_snap_object_context_set_editmesh_callbacks( + t->tsnap.object_context, + (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, + (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled, + (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled, + SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); } } } @@ -1335,6 +1343,20 @@ struct PeelRayCast_Data { ListBase *depth_peels; }; +struct PeelEditMeshRayCast_Data { + BVHTreeFromEditMesh bvhdata; + + /* internal vars for adding peel */ + Object *ob; + const float(*obmat)[4]; + const float(*timat)[3]; + + const float *ray_start; /* globalspace */ + + /* output list */ + ListBase *depth_peels; +}; + static void peelRayCast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { struct PeelRayCast_Data *data = userdata; @@ -1359,8 +1381,32 @@ static void peelRayCast_cb(void *userdata, int index, const BVHTreeRay *ray, BVH } } +static void peelEditMeshRayCast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + struct PeelEditMeshRayCast_Data *data = userdata; + + data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit); + + if (hit->index != -1) { + /* get all values in worldspace */ + float location[3], normal[3]; + float depth; + + /* worldspace location */ + mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co); + depth = len_v3v3(location, data->ray_start); + + /* worldspace normal */ + copy_v3_v3(normal, hit->no); + mul_m3_v3((float(*)[3])data->timat, normal); + normalize_v3(normal); + + addDepthPeel(data->depth_peels, depth, location, normal, data->ob); + } +} + static bool peelDerivedMesh( - Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], + Object *ob, DerivedMesh *dm, float obmat[4][4], const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]), ListBase *depth_peels) { @@ -1402,8 +1448,6 @@ static bool peelDerivedMesh( if (test == true) { struct PeelRayCast_Data data; - data.bvhdata.em_evil = em; - data.bvhdata.em_evil_all = false; bvhtree_from_mesh_looptri(&data.bvhdata, dm, 0.0f, 4, 6); if (data.bvhdata.tree != NULL) { @@ -1415,8 +1459,9 @@ static bool peelDerivedMesh( data.polynors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */ data.depth_peels = depth_peels; - BLI_bvhtree_ray_cast_all(data.bvhdata.tree, ray_start_local, ray_normal_local, 0.0f, - peelRayCast_cb, &data); + BLI_bvhtree_ray_cast_all( + data.bvhdata.tree, ray_start_local, ray_normal_local, 0.0f, + peelRayCast_cb, &data); } free_bvhtree_from_mesh(&data.bvhdata); @@ -1424,7 +1469,59 @@ static bool peelDerivedMesh( } return retval; -} +} + +static bool peelEditMesh( + Object *ob, BMEditMesh *em, float obmat[4][4], + const float ray_start[3], const float ray_normal[3], + ListBase *depth_peels) +{ + bool retval = false; + int totvert = em->bm->totvert; + + if (totvert > 0) { + float imat[4][4]; + float timat[3][3]; /* transpose inverse matrix for normals */ + float ray_start_local[3], ray_normal_local[3]; + bool test = true; + + invert_m4_m4(imat, obmat); + + transpose_m3_m4(timat, imat); + + mul_v3_m4v3(ray_start_local, imat, ray_start); + mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); + + if (test == true) { + struct PeelEditMeshRayCast_Data data; + + BLI_bitmap *looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__); + int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( + em->bm, looptri_mask, + BM_elem_cb_check_hflag_enabled_simple(BMFace *, (BM_ELEM_SELECT | BM_ELEM_HIDDEN))); + + bvhtree_from_editmesh_looptri_ex(&data.bvhdata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6); + + MEM_freeN(looptri_mask); + + if (data.bvhdata.tree != NULL) { + data.ob = ob; + data.obmat = (const float(*)[4])obmat; + data.timat = (const float(*)[3])timat; + data.ray_start = ray_start; + data.depth_peels = depth_peels; + + BLI_bvhtree_ray_cast_all( + data.bvhdata.tree, ray_start_local, ray_normal_local, 0.0f, + peelEditMeshRayCast_cb, &data); + } + + free_bvhtree_from_editmesh(&data.bvhdata); + } + } + + return retval; +} static bool peelObjects( Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, @@ -1452,24 +1549,21 @@ static bool peelObjects( if (dob->type == OB_MESH) { BMEditMesh *em; - DerivedMesh *dm = NULL; bool val; if (dob != obedit) { + DerivedMesh *dm; dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH); - - val = peelDerivedMesh(dob, dm, NULL, dob->obmat, ray_start, ray_normal, mval, r_depth_peels); + val = peelDerivedMesh(dob, dm, dob->obmat, ray_start, ray_normal, mval, r_depth_peels); + + dm->release(dm); } else { em = BKE_editmesh_from_object(dob); - dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); - - val = peelDerivedMesh(dob, dm, em, dob->obmat, ray_start, ray_normal, mval, r_depth_peels); + val = peelEditMesh(dob, em, dob->obmat, ray_start, ray_normal, r_depth_peels); } retval = retval || val; - - dm->release(dm); } } @@ -1482,14 +1576,14 @@ static bool peelObjects( if (ob != obedit && ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT))) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); + val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); dm->release(dm); } else if (ob == obedit && snap_select != SNAP_NOT_OBEDIT) { BMEditMesh *em = BKE_editmesh_from_object(ob); DerivedMesh *dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); - val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); + val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); dm->release(dm); } diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 074d79457d5..5174c2477b4 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -51,15 +51,30 @@ #include "BKE_tracking.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "ED_view3d.h" #include "ED_armature.h" #include "transform.h" typedef struct SnapObjectData { - BVHTreeFromMesh *bvh_trees[2]; + enum { + SNAP_MESH = 1, + SNAP_EDIT_MESH, + } type; } SnapObjectData; +typedef struct SnapObjectData_Mesh { + SnapObjectData sd; + BVHTreeFromMesh *bvh_trees[2]; + +} SnapObjectData_Mesh; + +typedef struct SnapObjectData_EditMesh { + SnapObjectData sd; + BVHTreeFromEditMesh *bvh_trees[2]; + +} SnapObjectData_EditMesh; struct SnapObjectContext { Main *bmain; @@ -81,8 +96,19 @@ struct SnapObjectContext { MemArena *mem_arena; } cache; + /* Filter data, returns true to check this value */ + struct { + struct { + bool (*test_vert_fn)(BMVert *, void *user_data); + bool (*test_edge_fn)(BMEdge *, void *user_data); + bool (*test_face_fn)(BMFace *, void *user_data); + void *user_data; + } edit_mesh; + } callbacks; + }; + /* -------------------------------------------------------------------- */ /** \name Internal Object Snapping API @@ -179,7 +205,7 @@ static bool snapEdge( } static bool snapVertex( - ARegion *ar, const float vco[3], const short vno[3], + ARegion *ar, const float vco[3], const float vno[3], float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px, const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, float r_loc[3], float r_no[3]) @@ -216,7 +242,7 @@ static bool snapVertex( copy_v3_v3(r_loc, location); if (r_no) { - normal_short_to_float_v3(r_no, vno); + copy_v3_v3(r_no, vno); mul_m3_v3(timat, r_no); normalize_v3(r_no); } @@ -543,7 +569,7 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) static bool snapDerivedMesh( SnapObjectContext *sctx, - Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], + Object *ob, DerivedMesh *dm, float obmat[4][4], const float mval[2], float *dist_px, const short snap_to, bool do_bb, const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, float r_loc[3], float r_no[3], int *r_index) @@ -579,19 +605,6 @@ static bool snapDerivedMesh( local_depth *= local_scale; } - SnapObjectData *sod = NULL; - - if (sctx->flag & SNAP_OBJECT_USE_CACHE) { - void **sod_p; - if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { - sod = *sod_p; - } - else { - sod = *sod_p = BLI_memarena_alloc(sctx->cache.mem_arena, sizeof(*sod)); - memset(sod, 0, sizeof(*sod)); - } - } - if (do_bb) { BoundBox *bb = BKE_object_boundbox_get(ob); @@ -619,9 +632,19 @@ static bool snapDerivedMesh( } } + SnapObjectData_Mesh *sod = NULL; BVHTreeFromMesh *treedata = NULL, treedata_stack; if (sctx->flag & SNAP_OBJECT_USE_CACHE) { + void **sod_p; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + sod = *sod_p; + } + else { + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_MESH; + } + int tree_index = -1; switch (snap_to) { case SCE_SNAP_MODE_FACE: @@ -633,7 +656,7 @@ static bool snapDerivedMesh( } if (tree_index != -1) { if (sod->bvh_trees[tree_index] == NULL) { - sod->bvh_trees[tree_index] = BLI_memarena_alloc(sctx->cache.mem_arena, sizeof(*treedata)); + sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); } treedata = sod->bvh_trees[tree_index]; } @@ -646,8 +669,6 @@ static bool snapDerivedMesh( } if (treedata) { - treedata->em_evil = em; - treedata->em_evil_all = false; switch (snap_to) { case SCE_SNAP_MODE_FACE: bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6); @@ -741,8 +762,10 @@ static bool snapDerivedMesh( &nearest, NULL, NULL) != -1) { const MVert *v = &treedata->vert[nearest.index]; + float vno[3]; + normal_short_to_float_v3(vno, v->no); retval = snapVertex( - ar, v->co, v->no, obmat, timat, mval, dist_px, + ar, v->co, vno, obmat, timat, mval, dist_px, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, r_no); } @@ -753,45 +776,247 @@ static bool snapDerivedMesh( MVert *verts = dm->getVertArray(dm); MEdge *edges = dm->getEdgeArray(dm); int totedge = dm->getNumEdges(dm); - const int *index_array = NULL; - int index = 0; - int i; - if (em != NULL) { - index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX); - BM_mesh_elem_table_ensure(em->bm, BM_EDGE); + for (int i = 0; i < totedge; i++) { + MEdge *e = edges + i; + retval |= snapEdge( + ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, + obmat, timat, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, r_no); } - for (i = 0; i < totedge; i++) { - MEdge *e = edges + i; - bool test = true; + break; + } + } - if (em != NULL) { - if (index_array) { - index = index_array[i]; - } - else { - index = i; - } + if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) { + if (treedata) { + free_bvhtree_from_mesh(treedata); + } + } + } - if (index == ORIGINDEX_NONE) { - test = false; - } - else { - BMEdge *eed = BM_edge_at_index(em->bm, index); + return retval; +} - if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN) || - BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || - BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) - { - test = false; - } + +static bool snapEditMesh( + SnapObjectContext *sctx, + Object *ob, BMEditMesh *em, float obmat[4][4], + const float mval[2], float *dist_px, const short snap_to, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + float r_loc[3], float r_no[3], int *r_index) +{ + ARegion *ar = sctx->v3d_data.ar; + bool retval = false; + int totvert = em->bm->totvert; + + if (totvert > 0) { + const bool do_ray_start_correction = ( + ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) && + (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp)); + + float imat[4][4]; + float timat[3][3]; /* transpose inverse matrix for normals */ + float ray_start_local[3], ray_normal_local[3]; + float local_scale, local_depth, len_diff; + + invert_m4_m4(imat, obmat); + transpose_m3_m4(timat, imat); + + copy_v3_v3(ray_start_local, ray_start); + copy_v3_v3(ray_normal_local, ray_normal); + + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + + /* local scale in normal direction */ + local_scale = normalize_v3(ray_normal_local); + local_depth = *ray_depth; + if (local_depth != BVH_RAYCAST_DIST_MAX) { + local_depth *= local_scale; + } + + SnapObjectData_EditMesh *sod = NULL; + + BVHTreeFromEditMesh *treedata = NULL, treedata_stack; + + if (sctx->flag & SNAP_OBJECT_USE_CACHE) { + void **sod_p; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + sod = *sod_p; + } + else { + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_EDIT_MESH; + } + + int tree_index = -1; + switch (snap_to) { + case SCE_SNAP_MODE_FACE: + tree_index = 1; + break; + case SCE_SNAP_MODE_VERTEX: + tree_index = 0; + break; + } + if (tree_index != -1) { + if (sod->bvh_trees[tree_index] == NULL) { + sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); + } + treedata = sod->bvh_trees[tree_index]; + } + } + else { + if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) { + treedata = &treedata_stack; + memset(treedata, 0, sizeof(*treedata)); + } + } + + if (treedata && treedata->tree == NULL) { + switch (snap_to) { + case SCE_SNAP_MODE_FACE: + { + BLI_bitmap *looptri_mask = NULL; + int looptri_num_active = -1; + if (sctx->callbacks.edit_mesh.test_face_fn) { + looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__); + looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( + em->bm, looptri_mask, + sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data); + } + bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6); + if (looptri_mask) { + MEM_freeN(looptri_mask); + } + break; + } + case SCE_SNAP_MODE_VERTEX: + { + BLI_bitmap *verts_mask = NULL; + int verts_num_active = -1; + if (sctx->callbacks.edit_mesh.test_vert_fn) { + verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__); + verts_num_active = BM_iter_mesh_bitmap_from_filter( + BM_VERTS_OF_MESH, em->bm, verts_mask, + (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn, + sctx->callbacks.edit_mesh.user_data); + } + bvhtree_from_editmesh_verts_ex(treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6); + if (verts_mask) { + MEM_freeN(verts_mask); + } + break; + } + } + } + + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already + * been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! + */ + if (do_ray_start_correction) { + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. + */ + if (treedata && treedata->tree != NULL) { + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); + if (nearest.index != -1) { + len_diff = sqrtf(nearest.dist_sq); + } + } + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far + * away ray_start values (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, + len_diff - len_v3v3(ray_start_local, ray_org_local)); + local_depth -= len_diff; + } + else { + len_diff = 0.0f; + } + + switch (snap_to) { + case SCE_SNAP_MODE_FACE: + { + BVHTreeRayHit hit; + + hit.index = -1; + hit.dist = local_depth; + + if (treedata->tree && + BLI_bvhtree_ray_cast(treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + copy_v3_v3(r_no, hit.no); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + + retval = true; + + if (r_index) { + *r_index = hit.index; } } + } + break; + } + case SCE_SNAP_MODE_VERTEX: + { + BVHTreeNearest nearest; - if (test) { + nearest.index = -1; + nearest.dist_sq = local_depth * local_depth; + if (treedata->tree && + BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_start_local, ray_normal_local, + &nearest, NULL, NULL) != -1) + { + const BMVert *v = BM_vert_at_index(em->bm, nearest.index); + retval = snapVertex( + ar, v->co, v->no, obmat, timat, mval, dist_px, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, r_no); + } + break; + } + case SCE_SNAP_MODE_EDGE: + { + BM_mesh_elem_table_ensure(em->bm, BM_EDGE); + int totedge = em->bm->totvert; + for (int i = 0; i < totedge; i++) { + BMEdge *eed = BM_edge_at_index(em->bm, i); + + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && + !BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) && + !BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) + { + short v1no[3], v2no[3]; + normal_float_to_short_v3(v1no, eed->v1->no); + normal_float_to_short_v3(v2no, eed->v2->no); retval |= snapEdge( - ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, + ar, eed->v1->co, v1no, eed->v2->co, v2no, obmat, timat, mval, dist_px, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, r_no); @@ -804,7 +1029,7 @@ static bool snapDerivedMesh( if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) { if (treedata) { - free_bvhtree_from_mesh(treedata); + free_bvhtree_from_editmesh(treedata); } } } @@ -826,17 +1051,18 @@ static bool snapObject( if (ob->type == OB_MESH) { BMEditMesh *em; - DerivedMesh *dm; - bool do_bb = true; if (use_obedit) { em = BKE_editmesh_from_object(ob); - dm = editbmesh_get_derived_cage(sctx->scene, ob, em, CD_MASK_BAREMESH); - do_bb = false; + retval = snapEditMesh( + sctx, ob, em, obmat, mval, dist_px, snap_to, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_index); } else { /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978. * still set the 'em' to NULL, since we only want the 'dm'. */ + DerivedMesh *dm; em = BKE_editmesh_from_object(ob); if (em) { editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); @@ -844,15 +1070,13 @@ static bool snapObject( else { dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH); } - em = NULL; - } - - retval = snapDerivedMesh( - sctx, ob, dm, em, obmat, mval, dist_px, snap_to, do_bb, - ray_start, ray_normal, ray_origin, ray_depth, - r_loc, r_no, r_index); + retval = snapDerivedMesh( + sctx, ob, dm, obmat, mval, dist_px, snap_to, true, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_index); - dm->release(dm); + dm->release(dm); + } } else if (ob->type == OB_ARMATURE) { retval = snapArmature( @@ -1014,12 +1238,28 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d( return sctx; } -static void snap_object_data_free(void *val) +static void snap_object_data_free(void *sod_v) { - SnapObjectData *sod = val; - for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) { - if (sod->bvh_trees[i]) { - free_bvhtree_from_mesh(sod->bvh_trees[i]); + switch (((SnapObjectData *)sod_v)->type) { + case SNAP_MESH: + { + SnapObjectData_Mesh *sod = sod_v; + for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) { + if (sod->bvh_trees[i]) { + free_bvhtree_from_mesh(sod->bvh_trees[i]); + } + } + break; + } + case SNAP_EDIT_MESH: + { + SnapObjectData_EditMesh *sod = sod_v; + for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) { + if (sod->bvh_trees[i]) { + free_bvhtree_from_editmesh(sod->bvh_trees[i]); + } + } + break; } } } @@ -1034,6 +1274,19 @@ void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) MEM_freeN(sctx); } +void ED_transform_snap_object_context_set_editmesh_callbacks( + SnapObjectContext *sctx, + bool (*test_vert_fn)(BMVert *, void *user_data), + bool (*test_edge_fn)(BMEdge *, void *user_data), + bool (*test_face_fn)(BMFace *, void *user_data), + void *user_data) +{ + sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn; + sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn; + sctx->callbacks.edit_mesh.test_face_fn = test_face_fn; + + sctx->callbacks.edit_mesh.user_data = user_data; +} bool ED_transform_snap_object_project_ray_ex( SnapObjectContext *sctx, diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 7de788dca56..c0b30f93939 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -83,6 +83,7 @@ set(SRC ../include/ED_space_api.h ../include/ED_text.h ../include/ED_transform.h + ../include/ED_transform_snap_object_context.h ../include/ED_transverts.h ../include/ED_types.h ../include/ED_util.h diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 9ba50641cc0..74fb4a08eda 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -55,6 +55,7 @@ #include "BKE_writeavi.h" #include "ED_transform.h" +#include "ED_transform_snap_object_context.h" #include "ED_uvedit.h" #ifdef WITH_PYTHON |