/* Raytracing for vertex to bone/vertex visibility */ static void heat_ray_tree_create(LaplacianSystem *sys) { MFace *mface = sys->heat.mface; float (*verts)[3] = sys->heat.verts; int totface = sys->heat.totface; int totvert = sys->heat.totvert; int a; sys->heat.bvhtree = BLI_bvhtree_new(totface, 0.0f, 4, 6); sys->heat.vface = MEM_callocN(sizeof(MFace*)*totvert, "HeatVFaces"); for(a=0; a<totface; a++) { MFace *mf = mface+a; float bb[6]; INIT_MINMAX(bb, bb+3); DO_MINMAX(verts[mf->v1], bb, bb+3); DO_MINMAX(verts[mf->v2], bb, bb+3); DO_MINMAX(verts[mf->v3], bb, bb+3); if(mf->v4) { DO_MINMAX(verts[mf->v4], bb, bb+3); } BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2); //Setup inverse pointers to use on isect.orig sys->heat.vface[mf->v1]= mf; sys->heat.vface[mf->v2]= mf; sys->heat.vface[mf->v3]= mf; if(mf->v4) sys->heat.vface[mf->v4]= mf; } BLI_bvhtree_balance(sys->heat.bvhtree); }
// 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; }
RayObject *RE_rayobject_blibvh_create(int size) { BVHObject *obj= (BVHObject*)MEM_callocN(sizeof(BVHObject), "BVHObject"); assert(RE_rayobject_isAligned(obj)); /* RayObject API assumes real data to be 4-byte aligned */ obj->rayobj.api = &bvh_api; obj->bvh = BLI_bvhtree_new(size, 0.0, 4, 6); obj->next_leaf = obj->leafs = (RayObject**)MEM_callocN(size*sizeof(RayObject*), "BVHObject leafs"); INIT_MINMAX(obj->bb[0], obj->bb[1]); return RE_rayobject_unalignRayAPI((RayObject*) obj); }
static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon) { unsigned int i; BVHTree *bvhtree; Cloth *cloth; ClothVertex *verts; MFace *mfaces; float co[12]; if(!clmd) return NULL; cloth = clmd->clothObject; if(!cloth) return NULL; verts = cloth->verts; mfaces = cloth->mfaces; // in the moment, return zero if no faces there if(!cloth->numfaces) return NULL; // create quadtree with k=26 bvhtree = BLI_bvhtree_new(cloth->numfaces, epsilon, 4, 26); // fill tree for(i = 0; i < cloth->numfaces; i++, mfaces++) { copy_v3_v3(&co[0*3], verts[mfaces->v1].xold); copy_v3_v3(&co[1*3], verts[mfaces->v2].xold); copy_v3_v3(&co[2*3], verts[mfaces->v3].xold); if(mfaces->v4) copy_v3_v3(&co[3*3], verts[mfaces->v4].xold); BLI_bvhtree_insert(bvhtree, i, co, (mfaces->v4 ? 4 : 3)); } // balance tree BLI_bvhtree_balance(bvhtree); return bvhtree; }
static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon) { unsigned int i; BVHTree *bvhtree; Cloth *cloth; ClothVertex *verts; const MVertTri *vt; if (!clmd) return NULL; cloth = clmd->clothObject; if (!cloth) return NULL; verts = cloth->verts; vt = cloth->tri; /* in the moment, return zero if no faces there */ if (!cloth->tri_num) return NULL; /* create quadtree with k=26 */ bvhtree = BLI_bvhtree_new(cloth->tri_num, epsilon, 4, 26); /* fill tree */ for (i = 0; i < cloth->tri_num; i++, vt++) { float co[3][3]; copy_v3_v3(co[0], verts[vt->tri[0]].xold); copy_v3_v3(co[1], verts[vt->tri[1]].xold); copy_v3_v3(co[2], verts[vt->tri[2]].xold); BLI_bvhtree_insert(bvhtree, i, co[0], 3); } /* balance tree */ BLI_bvhtree_balance(bvhtree); return bvhtree; }
static void pointdensity_cache_object(Scene *scene, PointDensity *pd, Object *ob) { int i; DerivedMesh *dm; MVert *mvert = NULL; dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); mvert = dm->getVertArray(dm); /* local object space */ pd->totpoints = dm->getNumVerts(dm); if (pd->totpoints == 0) { return; } pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6); for (i = 0; i < pd->totpoints; i++, mvert++) { float co[3]; copy_v3_v3(co, mvert->co); switch (pd->ob_cache_space) { case TEX_PD_OBJECTSPACE: break; case TEX_PD_OBJECTLOC: mul_m4_v3(ob->obmat, co); sub_v3_v3(co, ob->loc); break; case TEX_PD_WORLDSPACE: default: mul_m4_v3(ob->obmat, co); break; } BLI_bvhtree_insert(pd->point_tree, i, co, 1); } BLI_bvhtree_balance(pd->point_tree); dm->release(dm); }
static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon) { unsigned int i; BVHTree *bvhtree; Cloth *cloth; ClothVertex *verts; MFace *mfaces; float co[12]; if(!clmd) return NULL; cloth = clmd->clothObject; if(!cloth) return NULL; verts = cloth->verts; mfaces = cloth->mfaces; // in the moment, return zero if no faces there if(!cloth->numverts) return NULL; // create quadtree with k=26 bvhtree = BLI_bvhtree_new(cloth->numverts, epsilon, 4, 6); // fill tree for(i = 0; i < cloth->numverts; i++, verts++) { VECCOPY(&co[0*3], verts->xold); BLI_bvhtree_insert(bvhtree, i, co, 1); } // balance tree BLI_bvhtree_balance(bvhtree); return bvhtree; }
static BVHTree *bvhtree_from_mesh_verts_create_tree( float epsilon, int tree_type, int axis, MVert *vert, const int numVerts, BLI_bitmap *mask, int numVerts_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)) { numVerts_active++; } } } else if (!mask) { numVerts_active = numVerts; } tree = BLI_bvhtree_new(numVerts_active, epsilon, tree_type, axis); if (tree) { for (i = 0; i < numVerts; i++) { if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) { continue; } BLI_bvhtree_insert(tree, i, vert[i].co, 1); } BLI_bvhtree_balance(tree); } } return tree; }
static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon) { unsigned int i; BVHTree *bvhtree; Cloth *cloth; ClothVertex *verts; if (!clmd) return NULL; cloth = clmd->clothObject; if (!cloth) return NULL; verts = cloth->verts; /* in the moment, return zero if no faces there */ if (!cloth->mvert_num) return NULL; /* create quadtree with k=26 */ bvhtree = BLI_bvhtree_new(cloth->mvert_num, epsilon, 4, 6); /* fill tree */ for (i = 0; i < cloth->mvert_num; i++, verts++) { const float *co; co = verts->xold; BLI_bvhtree_insert(bvhtree, i, co, 1); } /* balance tree */ BLI_bvhtree_balance(bvhtree); return bvhtree; }
/* Raytracing for vertex to bone/vertex visibility */ static void heat_ray_tree_create(LaplacianSystem *sys) { const MLoopTri *looptri = sys->heat.mlooptri; const MLoop *mloop = sys->heat.mloop; float (*verts)[3] = sys->heat.verts; int tottri = sys->heat.tottri; int totvert = sys->heat.totvert; int a; sys->heat.bvhtree = BLI_bvhtree_new(tottri, 0.0f, 4, 6); sys->heat.vltree = MEM_callocN(sizeof(MLoopTri *) * totvert, "HeatVFaces"); for (a = 0; a < tottri; a++) { const MLoopTri *lt = &looptri[a]; float bb[6]; int vtri[3]; vtri[0] = mloop[lt->tri[0]].v; vtri[1] = mloop[lt->tri[1]].v; vtri[2] = mloop[lt->tri[2]].v; INIT_MINMAX(bb, bb + 3); minmax_v3v3_v3(bb, bb + 3, verts[vtri[0]]); minmax_v3v3_v3(bb, bb + 3, verts[vtri[1]]); minmax_v3v3_v3(bb, bb + 3, verts[vtri[2]]); BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2); //Setup inverse pointers to use on isect.orig sys->heat.vltree[vtri[0]] = lt; sys->heat.vltree[vtri[1]] = lt; sys->heat.vltree[vtri[2]] = lt; } BLI_bvhtree_balance(sys->heat.bvhtree); }
static void pointdensity_cache_psys(Scene *scene, PointDensity *pd, Object *ob, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy) { DerivedMesh *dm; ParticleKey state; ParticleCacheKey *cache; ParticleSimulationData sim = {NULL}; ParticleData *pa = NULL; float cfra = BKE_scene_frame_get(scene); int i /*, childexists*/ /* UNUSED */; int total_particles, offset = 0; int data_used = point_data_used(pd); float partco[3]; /* init everything */ if (!psys || !ob || !pd) { return; } /* Just to create a valid rendering context for particles */ psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0); dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); if ( !psys_check_enabled(ob, psys)) { psys_render_restore(ob, psys); return; } sim.scene = scene; sim.ob = ob; sim.psys = psys; sim.psmd = psys_get_modifier(ob, psys); /* in case ob->imat isn't up-to-date */ invert_m4_m4(ob->imat, ob->obmat); total_particles = psys->totpart + psys->totchild; psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); alloc_point_data(pd, total_particles, data_used); pd->totpoints = total_particles; if (data_used & POINT_DATA_VEL) { offset = pd->totpoints * 3; } #if 0 /* UNUSED */ if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; #endif for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) { if (psys->part->type == PART_HAIR) { /* hair particles */ if (i < psys->totpart && psys->pathcache) cache = psys->pathcache[i]; else if (i >= psys->totpart && psys->childcache) cache = psys->childcache[i - psys->totpart]; else continue; cache += cache->segments; /* use endpoint */ copy_v3_v3(state.co, cache->co); zero_v3(state.vel); state.time = 0.0f; } else { /* emitter particles */ state.time = cfra; if (!psys_get_particle_state(&sim, i, &state, 0)) continue; if (data_used & POINT_DATA_LIFE) { if (i < psys->totpart) { state.time = (cfra - pa->time) / pa->lifetime; } else { ChildParticle *cpa = (psys->child + i) - psys->totpart; float pa_birthtime, pa_dietime; state.time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); } } } copy_v3_v3(partco, state.co); if (pd->psys_cache_space == TEX_PD_OBJECTSPACE) mul_m4_v3(ob->imat, partco); else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { sub_v3_v3(partco, ob->loc); } else { /* TEX_PD_WORLDSPACE */ } BLI_bvhtree_insert(pd->point_tree, i, partco, 1); if (data_used & POINT_DATA_VEL) { pd->point_data[i * 3 + 0] = state.vel[0]; pd->point_data[i * 3 + 1] = state.vel[1]; pd->point_data[i * 3 + 2] = state.vel[2]; } if (data_used & POINT_DATA_LIFE) { pd->point_data[offset + i] = state.time; } } BLI_bvhtree_balance(pd->point_tree); dm->release(dm); if (psys->lattice_deform_data) { end_latt_deform(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } psys_render_restore(ob, psys); }
static BVHTree *bvhtree_from_mesh_looptri_create_tree( float epsilon, int tree_type, int axis, BMEditMesh *em, const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num, BLI_bitmap *mask, int looptri_num_active) { BVHTree *tree = NULL; int i; if (looptri_num) { if (mask && looptri_num_active < 0) { looptri_num_active = 0; for (i = 0; i < looptri_num; i++) { if (BLI_BITMAP_TEST_BOOL(mask, i)) { looptri_num_active++; } } } else if (!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 (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 (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 (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 && looptri) { for (i = 0; i < looptri_num; i++) { float co[4][3]; if (mask && !BLI_BITMAP_TEST_BOOL(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); } } return 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; }
static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys) { DerivedMesh* dm; ParticleKey state; ParticleSimulationData sim= {NULL}; ParticleData *pa=NULL; float cfra = BKE_curframe(re->scene); int i, childexists; int total_particles, offset=0; int data_used = point_data_used(pd); float partco[3]; float obview[4][4]; /* init everything */ if (!psys || !ob || !pd) return; mul_m4_m4m4(obview, re->viewinv, ob->obmat); /* Just to create a valid rendering context for particles */ psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0); dm = mesh_create_derived_render(re->scene, ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); if ( !psys_check_enabled(ob, psys)) { psys_render_restore(ob, psys); return; } sim.scene= re->scene; sim.ob= ob; sim.psys= psys; /* in case ob->imat isn't up-to-date */ invert_m4_m4(ob->imat, ob->obmat); total_particles = psys->totpart+psys->totchild; psys->lattice=psys_get_lattice(&sim); pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); alloc_point_data(pd, total_particles, data_used); pd->totpoints = total_particles; if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3; if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; for (i=0, pa=psys->particles; i < total_particles; i++, pa++) { state.time = cfra; if(psys_get_particle_state(&sim, i, &state, 0)) { VECCOPY(partco, state.co); if (pd->psys_cache_space == TEX_PD_OBJECTSPACE) mul_m4_v3(ob->imat, partco); else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { sub_v3_v3(partco, ob->loc); } else { /* TEX_PD_WORLDSPACE */ } BLI_bvhtree_insert(pd->point_tree, i, partco, 1); if (data_used & POINT_DATA_VEL) { pd->point_data[i*3 + 0] = state.vel[0]; pd->point_data[i*3 + 1] = state.vel[1]; pd->point_data[i*3 + 2] = state.vel[2]; } if (data_used & POINT_DATA_LIFE) { float pa_time; if (i < psys->totpart) { pa_time = (cfra - pa->time)/pa->lifetime; } else { ChildParticle *cpa= (psys->child + i) - psys->totpart; float pa_birthtime, pa_dietime; pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); } pd->point_data[offset + i] = pa_time; } } } BLI_bvhtree_balance(pd->point_tree); dm->release(dm); if(psys->lattice){ end_latt_deform(psys->lattice); psys->lattice=0; } psys_render_restore(ob, psys); }
/* 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; }
BMBVHTree *BKE_bmbvh_new_ex( BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag, const float (*cos_cage)[3], const bool cos_cage_free, bool (*test_fn)(BMFace *, void *user_data), void *user_data) { /* could become argument */ const float epsilon = FLT_EPSILON * 2.0f; BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree"); float cos[3][3]; int i; int tottri; /* avoid testing every tri */ BMFace *f_test, *f_test_prev; bool test_fn_ret; /* BKE_editmesh_tessface_calc() must be called already */ BLI_assert(looptris_tot != 0 || bm->totface == 0); if (cos_cage) { BM_mesh_elem_index_ensure(bm, BM_VERT); } bmtree->looptris = looptris; bmtree->looptris_tot = looptris_tot; bmtree->bm = bm; bmtree->cos_cage = cos_cage; bmtree->cos_cage_free = cos_cage_free; bmtree->flag = flag; if (test_fn) { /* callback must do... */ BLI_assert(!(flag & (BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN))); f_test_prev = NULL; test_fn_ret = false; tottri = 0; for (i = 0; i < looptris_tot; i++) { f_test = looptris[i][0]->f; if (f_test != f_test_prev) { test_fn_ret = test_fn(f_test, user_data); f_test_prev = f_test; } if (test_fn_ret) { tottri++; } } } else { tottri = looptris_tot; } bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8); f_test_prev = NULL; test_fn_ret = false; for (i = 0; i < looptris_tot; i++) { if (test_fn) { /* note, the arrays wont align now! take care */ f_test = looptris[i][0]->f; if (f_test != f_test_prev) { test_fn_ret = test_fn(f_test, user_data); f_test_prev = f_test; } if (!test_fn_ret) { continue; } } if (cos_cage) { copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]); copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]); copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]); } else { copy_v3_v3(cos[0], looptris[i][0]->v->co); copy_v3_v3(cos[1], looptris[i][1]->v->co); copy_v3_v3(cos[2], looptris[i][2]->v->co); } BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3); } BLI_bvhtree_balance(bmtree->tree); return bmtree; }
// 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; }
/* 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; }
BMBVHTree *BKE_bmbvh_new(BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free) { /* could become argument */ const float epsilon = FLT_EPSILON * 2.0f; struct BMLoop *(*looptris)[3] = em->looptris; BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree"); float cos[3][3]; int i; int tottri; /* BKE_editmesh_tessface_calc() must be called already */ BLI_assert(em->tottri != 0 || em->bm->totface == 0); if (cos_cage) { BM_mesh_elem_index_ensure(em->bm, BM_VERT); } bmtree->em = em; bmtree->bm = em->bm; bmtree->cos_cage = cos_cage; bmtree->cos_cage_free = cos_cage_free; bmtree->flag = flag; if (flag & (BMBVH_RESPECT_SELECT)) { tottri = 0; for (i = 0; i < em->tottri; i++) { if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) { tottri++; } } } else if (flag & (BMBVH_RESPECT_HIDDEN)) { tottri = 0; for (i = 0; i < em->tottri; i++) { if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { tottri++; } } } else { tottri = em->tottri; } bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8); for (i = 0; i < em->tottri; i++) { if (flag & BMBVH_RESPECT_SELECT) { /* note, the arrays wont align now! take care */ if (!BM_elem_flag_test(em->looptris[i][0]->f, BM_ELEM_SELECT)) { continue; } } else if (flag & BMBVH_RESPECT_HIDDEN) { /* note, the arrays wont align now! take care */ if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { continue; } } if (cos_cage) { copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]); copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]); copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]); } else { copy_v3_v3(cos[0], looptris[i][0]->v->co); copy_v3_v3(cos[1], looptris[i][1]->v->co); copy_v3_v3(cos[2], looptris[i][2]->v->co); } BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3); } BLI_bvhtree_balance(bmtree->tree); return bmtree; }