/* 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) { BMEditMesh *em = data->em_evil; const int bvhcache_type = em ? BVHTREE_FROM_FACES_EDITMESH : 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); 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); } /* Not in cache */ if (tree == NULL) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); tree = bvhcache_find(&dm->bvhCache, bvhcache_type); 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)); } tree = bvhtree_from_mesh_faces_create_tree(epsilon, tree_type, axis, em, 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); } } BLI_rw_mutex_unlock(&cache_rwlock); } else { /* printf("BVHTree is already build, using cached tree\n"); */ } /* Setup BVHTreeFromMesh */ bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, em, vert, vert_allocated, face, face_allocated); return data->tree; }
/* Builds a bvh tree.. where nodes are the faces of the given dm. */ 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 ? BVHTREE_FROM_FACES_EDITMESH : BVHTREE_FROM_FACES; BVHTree *tree; MVert *vert; MFace *face; bool vert_allocated = false, face_allocated = false; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); tree = bvhcache_find(&dm->bvhCache, bvhcache_type); 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); } /* Not in cache */ if (tree == NULL) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); tree = bvhcache_find(&dm->bvhCache, bvhcache_type); if (tree == NULL) { int i; 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)); } if (numFaces != 0) { /* Create a bvh-tree of the given target */ // printf("%s: building BVH, total=%d\n", __func__, numFaces); tree = BLI_bvhtree_new(numFaces, epsilon, tree_type, axis); if (tree != NULL) { 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 < em->tottri; i++) { const BMLoop **ltri = looptris[i]; BMFace *f = ltri[0]->f; bool insert; /* Start with the assumption the triangle should be included for snapping. */ if (f == f_prev) { insert = insert_prev; } 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; insert = true; 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 (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); BLI_bvhtree_insert(tree, i, co[0], 3); } } } else { if (vert != NULL && face != NULL) { for (i = 0; i < numFaces; i++) { float co[4][3]; 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_balance(tree); /* Save on cache for later use */ // printf("BVHTree built and saved on cache\n"); bvhcache_insert(&dm->bvhCache, tree, bvhcache_type); } } } BLI_rw_mutex_unlock(&cache_rwlock); } else { // printf("BVHTree is already build, using cached tree\n"); } /* Setup BVHTreeFromMesh */ memset(data, 0, sizeof(*data)); data->tree = tree; data->em_evil = em; if (data->tree) { data->cached = true; if (em) { data->nearest_callback = editmesh_faces_nearest_point; data->raycast_callback = editmesh_faces_spherecast; } else { data->nearest_callback = mesh_faces_nearest_point; data->raycast_callback = mesh_faces_spherecast; data->vert = vert; data->vert_allocated = vert_allocated; data->face = face; data->face_allocated = face_allocated; } data->sphere_radius = epsilon; } else { if (vert_allocated) { MEM_freeN(vert); } if (face_allocated) { MEM_freeN(face); } } return data->tree; }
/* Builds a bvh tree.. where nodes are the vertexs of the given mesh */ BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) { BVHTree *tree; MVert *vert; bool vert_allocated; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTICES); BLI_rw_mutex_unlock(&cache_rwlock); vert = DM_get_vert_array(dm, &vert_allocated); /* Not in cache */ if (tree == NULL) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTICES); if (tree == NULL) { int i; int numVerts = dm->getNumVerts(dm); if (vert != NULL) { tree = BLI_bvhtree_new(numVerts, epsilon, tree_type, axis); if (tree != NULL) { for (i = 0; i < numVerts; i++) { BLI_bvhtree_insert(tree, i, vert[i].co, 1); } BLI_bvhtree_balance(tree); /* Save on cache for later use */ // printf("BVHTree built and saved on cache\n"); bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTICES); } } } BLI_rw_mutex_unlock(&cache_rwlock); } else { // printf("BVHTree is already build, using cached tree\n"); } /* Setup BVHTreeFromMesh */ memset(data, 0, sizeof(*data)); data->tree = tree; if (data->tree) { data->cached = true; /* a NULL nearest callback works fine * remember the min distance to point is the same as the min distance to BV of point */ data->nearest_callback = NULL; data->raycast_callback = NULL; data->vert = vert; data->vert_allocated = vert_allocated; data->face = DM_get_tessface_array(dm, &data->face_allocated); data->sphere_radius = epsilon; } else { if (vert_allocated) { MEM_freeN(vert); } } return data->tree; }