/* 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 *tree; MVert *vert; bool vert_allocated; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTS); 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_VERTS); if (tree == NULL) { tree = bvhtree_from_mesh_verts_create_tree(epsilon, tree_type, axis, vert, dm->getNumVerts(dm), NULL, -1); if (tree) { /* Save on cache for later use */ /* printf("BVHTree built and saved on cache\n"); */ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS); } } BLI_rw_mutex_unlock(&cache_rwlock); } else { /* printf("BVHTree is already build, using cached tree\n"); */ } /* Setup BVHTreeFromMesh */ bvhtree_from_mesh_verts_setup_data(data, tree, true, epsilon, vert, vert_allocated); return data->tree; }
/* 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 mesh. BVHTree* bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) { BVHTree *tree = bvhcache_find(&mesh->bvhCache, BVHTREE_FROM_EDGES); //Not in cache if(tree == NULL) { int i; int numEdges= mesh->getNumEdges(mesh); MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); MEdge *edge = mesh->getEdgeDataArray(mesh, CD_MEDGE); if(vert != NULL && edge != NULL) { /* Create a bvh-tree of the given target */ tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis); if(tree != NULL) { for(i = 0; i < numEdges; i++) { float co[4][3]; VECCOPY(co[0], vert[ edge[i].v1 ].co); VECCOPY(co[1], vert[ edge[i].v2 ].co); BLI_bvhtree_insert(tree, i, co[0], 2); } BLI_bvhtree_balance(tree); //Save on cache for later use // printf("BVHTree built and saved on cache\n"); bvhcache_insert(&mesh->bvhCache, tree, BVHTREE_FROM_EDGES); } } } 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; data->nearest_callback = mesh_edges_nearest_point; data->raycast_callback = NULL; data->mesh = mesh; data->vert = mesh->getVertDataArray(mesh, CD_MVERT); data->edge = mesh->getEdgeDataArray(mesh, CD_MEDGE); data->sphere_radius = epsilon; } return data->tree; }
// Builds a bvh tree.. where nodes are the vertexs of the given mesh BVHTree* bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) { BVHTree *tree = bvhcache_find(&mesh->bvhCache, BVHTREE_FROM_VERTICES); //Not in cache if(tree == NULL) { int i; int numVerts= mesh->getNumVerts(mesh); MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); 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(&mesh->bvhCache, tree, BVHTREE_FROM_VERTICES); } } } 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 //remeber 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->mesh = mesh; data->vert = mesh->getVertDataArray(mesh, CD_MVERT); data->face = mesh->getFaceDataArray(mesh, CD_MFACE); data->sphere_radius = epsilon; } return data->tree; }
void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type) { BVHCacheItem *item = NULL; assert(tree != NULL); assert(bvhcache_find(cache, type) == NULL); item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem"); assert(item != NULL); item->type = type; item->tree = tree; BLI_linklist_prepend(cache, item); }
/** * 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) { BMEditMesh *em = data->em_evil; const int bvhcache_type = em ? BVHTREE_FROM_FACES_EDITMESH : BVHTREE_FROM_LOOPTRI; BVHTree *tree; MVert *mvert = NULL; MLoop *mloop = NULL; const MLoopTri *looptri = NULL; bool vert_allocated = false; bool loop_allocated = false; bool looptri_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) { MPoly *mpoly; bool poly_allocated = false; 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); } } /* 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 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)); } tree = bvhtree_from_mesh_looptri_create_tree( epsilon, tree_type, axis, em, 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); } } BLI_rw_mutex_unlock(&cache_rwlock); } else { /* printf("BVHTree is already build, using cached tree\n"); */ } /* Setup BVHTreeFromMesh */ bvhtree_from_mesh_looptri_setup_data( data, tree, true, epsilon, em, mvert, vert_allocated, mloop, loop_allocated, looptri, looptri_allocated); return data->tree; }
/* 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 *tree; MVert *vert; MEdge *edge; bool vert_allocated, edge_allocated; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_EDGES); BLI_rw_mutex_unlock(&cache_rwlock); vert = DM_get_vert_array(dm, &vert_allocated); edge = DM_get_edge_array(dm, &edge_allocated); /* Not in cache */ if (tree == NULL) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_EDGES); if (tree == NULL) { int i; int numEdges = dm->getNumEdges(dm); if (vert != NULL && edge != NULL) { /* Create a bvh-tree of the given target */ tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis); if (tree != NULL) { for (i = 0; i < numEdges; i++) { float co[4][3]; copy_v3_v3(co[0], vert[edge[i].v1].co); copy_v3_v3(co[1], vert[edge[i].v2].co); BLI_bvhtree_insert(tree, i, co[0], 2); } 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_EDGES); } } } 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; data->nearest_callback = mesh_edges_nearest_point; data->raycast_callback = mesh_edges_spherecast; data->vert = vert; data->vert_allocated = vert_allocated; data->edge = edge; data->edge_allocated = edge_allocated; data->sphere_radius = epsilon; } else { if (vert_allocated) { MEM_freeN(vert); } if (edge_allocated) { MEM_freeN(edge); } } 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) { BVHTree *tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_FACES); BMEditMesh *em = data->em_evil; /* Not in cache */ 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 { MVert *vert = dm->getVertDataArray(dm, CD_MVERT); MFace *face = dm->getTessFaceDataArray(dm, CD_MFACE); 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, BVHTREE_FROM_FACES); } } } 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 = dm->getVertDataArray(dm, CD_MVERT); data->face = dm->getTessFaceDataArray(dm, CD_MFACE); } data->sphere_radius = epsilon; } 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; }
// Builds a bvh tree.. where nodes are the faces of the given mesh. BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) { BVHTree *tree = bvhcache_find(&mesh->bvhCache, BVHTREE_FROM_FACES); //Not in cache if(tree == NULL) { int i; int numFaces= mesh->getNumFaces(mesh); MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE); if(vert != NULL && face != NULL) { /* Create a bvh-tree of the given target */ tree = BLI_bvhtree_new(numFaces, epsilon, tree_type, axis); if(tree != NULL) { /* XXX, for snap only, em & dm are assumed to be aligned, since dm is the em's cage */ EditMesh *em= data->em_evil; if(em) { EditFace *efa= em->faces.first; for(i = 0; i < numFaces; i++, efa= efa->next) { if(!(efa->f & 1) && efa->h==0 && !((efa->v1->f&1)+(efa->v2->f&1)+(efa->v3->f&1)+(efa->v4?efa->v4->f&1:0))) { float co[4][3]; VECCOPY(co[0], vert[ face[i].v1 ].co); VECCOPY(co[1], vert[ face[i].v2 ].co); VECCOPY(co[2], vert[ face[i].v3 ].co); if(face[i].v4) VECCOPY(co[3], vert[ face[i].v4 ].co); BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); } } } else { for(i = 0; i < numFaces; i++) { float co[4][3]; VECCOPY(co[0], vert[ face[i].v1 ].co); VECCOPY(co[1], vert[ face[i].v2 ].co); VECCOPY(co[2], vert[ face[i].v3 ].co); if(face[i].v4) VECCOPY(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(&mesh->bvhCache, tree, BVHTREE_FROM_FACES); } } } 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; data->nearest_callback = mesh_faces_nearest_point; data->raycast_callback = mesh_faces_spherecast; data->mesh = mesh; data->vert = mesh->getVertDataArray(mesh, CD_MVERT); data->face = mesh->getFaceDataArray(mesh, CD_MFACE); data->sphere_radius = epsilon; } return data->tree; }