This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenkernel/intern/bvhutils.c
Sergey Sharybin e08db08a84 Fix T39997: Multiple boolean modifiers sharing the same right operand crashes
The issue was caused by the temporary CD layers being allocated for subsurf
meshes, same as we've got back in 881fb43.

In the long run this temporary storage is to be re-considered, but it'll also
imply re-considering of the Derivedmesh interaction as well. For now let's
use a simpler solution which is forbidding modifiers to call getArray for other
objects' derivedMeshes but use an API calls which would allocate local copy of
the data preventing race condition of shared data in DM.
2014-05-03 16:13:01 +02:00

934 lines
22 KiB
C

/*
* ***** 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.
*
* The Original Code is Copyright (C) Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Andr Pinto.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/bvhutils.c
* \ingroup bke
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_threads.h"
#include "BKE_DerivedMesh.h"
#include "BKE_editmesh.h"
#include "MEM_guardedalloc.h"
static ThreadRWMutex cache_rwlock = BLI_RWLOCK_INITIALIZER;
/* Math stuff for ray casting on mesh faces and for nearest surface */
float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, const float UNUSED(m_dist), const float v0[3], const float v1[3], const float v2[3])
{
float dist;
if (isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON))
return dist;
return FLT_MAX;
}
static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, const float m_dist, const float v0[3], const float v1[3], const float v2[3])
{
float idist;
float p1[3];
float plane_normal[3], hit_point[3];
normal_tri_v3(plane_normal, v0, v1, v2);
madd_v3_v3v3fl(p1, ray->origin, ray->direction, m_dist);
if (isect_sweeping_sphere_tri_v3(ray->origin, p1, radius, v0, v1, v2, &idist, hit_point)) {
return idist * m_dist;
}
return FLT_MAX;
}
/*
* Function adapted from David Eberly's distance tools (LGPL)
* http://www.geometrictools.com/LibFoundation/Distance/Distance.html
*/
float nearest_point_in_tri_surface_squared(
const float v0[3], const float v1[3], const float v2[3],
const float p[3], int *v, int *e, float nearest[3])
{
float diff[3];
float e0[3];
float e1[3];
float A00;
float A01;
float A11;
float B0;
float B1;
float C;
float Det;
float S;
float T;
float sqrDist;
int lv = -1, le = -1;
sub_v3_v3v3(diff, v0, p);
sub_v3_v3v3(e0, v1, v0);
sub_v3_v3v3(e1, v2, v0);
A00 = dot_v3v3(e0, e0);
A01 = dot_v3v3(e0, e1);
A11 = dot_v3v3(e1, e1);
B0 = dot_v3v3(diff, e0);
B1 = dot_v3v3(diff, e1);
C = dot_v3v3(diff, diff);
Det = fabsf(A00 * A11 - A01 * A01);
S = A01 * B1 - A11 * B0;
T = A01 * B0 - A00 * B1;
if (S + T <= Det) {
if (S < 0.0f) {
if (T < 0.0f) { /* Region 4 */
if (B0 < 0.0f) {
T = 0.0f;
if (-B0 >= A00) {
S = 1.0f;
sqrDist = A00 + 2.0f * B0 + C;
lv = 1;
}
else {
if (fabsf(A00) > FLT_EPSILON)
S = -B0 / A00;
else
S = 0.0f;
sqrDist = B0 * S + C;
le = 0;
}
}
else {
S = 0.0f;
if (B1 >= 0.0f) {
T = 0.0f;
sqrDist = C;
lv = 0;
}
else if (-B1 >= A11) {
T = 1.0f;
sqrDist = A11 + 2.0f * B1 + C;
lv = 2;
}
else {
if (fabsf(A11) > FLT_EPSILON)
T = -B1 / A11;
else
T = 0.0f;
sqrDist = B1 * T + C;
le = 1;
}
}
}
else { /* Region 3 */
S = 0.0f;
if (B1 >= 0.0f) {
T = 0.0f;
sqrDist = C;
lv = 0;
}
else if (-B1 >= A11) {
T = 1.0f;
sqrDist = A11 + 2.0f * B1 + C;
lv = 2;
}
else {
if (fabsf(A11) > FLT_EPSILON)
T = -B1 / A11;
else
T = 0.0;
sqrDist = B1 * T + C;
le = 1;
}
}
}
else if (T < 0.0f) { /* Region 5 */
T = 0.0f;
if (B0 >= 0.0f) {
S = 0.0f;
sqrDist = C;
lv = 0;
}
else if (-B0 >= A00) {
S = 1.0f;
sqrDist = A00 + 2.0f * B0 + C;
lv = 1;
}
else {
if (fabsf(A00) > FLT_EPSILON)
S = -B0 / A00;
else
S = 0.0f;
sqrDist = B0 * S + C;
le = 0;
}
}
else { /* Region 0 */
/* Minimum at interior lv */
float invDet;
if (fabsf(Det) > FLT_EPSILON)
invDet = 1.0f / Det;
else
invDet = 0.0f;
S *= invDet;
T *= invDet;
sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
T * (A01 * S + A11 * T + 2.0f * B1) + C;
}
}
else {
float tmp0, tmp1, numer, denom;
if (S < 0.0f) { /* Region 2 */
tmp0 = A01 + B0;
tmp1 = A11 + B1;
if (tmp1 > tmp0) {
numer = tmp1 - tmp0;
denom = A00 - 2.0f * A01 + A11;
if (numer >= denom) {
S = 1.0f;
T = 0.0f;
sqrDist = A00 + 2.0f * B0 + C;
lv = 1;
}
else {
if (fabsf(denom) > FLT_EPSILON)
S = numer / denom;
else
S = 0.0f;
T = 1.0f - S;
sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
T * (A01 * S + A11 * T + 2.0f * B1) + C;
le = 2;
}
}
else {
S = 0.0f;
if (tmp1 <= 0.0f) {
T = 1.0f;
sqrDist = A11 + 2.0f * B1 + C;
lv = 2;
}
else if (B1 >= 0.0f) {
T = 0.0f;
sqrDist = C;
lv = 0;
}
else {
if (fabsf(A11) > FLT_EPSILON)
T = -B1 / A11;
else
T = 0.0f;
sqrDist = B1 * T + C;
le = 1;
}
}
}
else if (T < 0.0f) { /* Region 6 */
tmp0 = A01 + B1;
tmp1 = A00 + B0;
if (tmp1 > tmp0) {
numer = tmp1 - tmp0;
denom = A00 - 2.0f * A01 + A11;
if (numer >= denom) {
T = 1.0f;
S = 0.0f;
sqrDist = A11 + 2.0f * B1 + C;
lv = 2;
}
else {
if (fabsf(denom) > FLT_EPSILON)
T = numer / denom;
else
T = 0.0f;
S = 1.0f - T;
sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
T * (A01 * S + A11 * T + 2.0f * B1) + C;
le = 2;
}
}
else {
T = 0.0f;
if (tmp1 <= 0.0f) {
S = 1.0f;
sqrDist = A00 + 2.0f * B0 + C;
lv = 1;
}
else if (B0 >= 0.0f) {
S = 0.0f;
sqrDist = C;
lv = 0;
}
else {
if (fabsf(A00) > FLT_EPSILON)
S = -B0 / A00;
else
S = 0.0f;
sqrDist = B0 * S + C;
le = 0;
}
}
}
else { /* Region 1 */
numer = A11 + B1 - A01 - B0;
if (numer <= 0.0f) {
S = 0.0f;
T = 1.0f;
sqrDist = A11 + 2.0f * B1 + C;
lv = 2;
}
else {
denom = A00 - 2.0f * A01 + A11;
if (numer >= denom) {
S = 1.0f;
T = 0.0f;
sqrDist = A00 + 2.0f * B0 + C;
lv = 1;
}
else {
if (fabsf(denom) > FLT_EPSILON)
S = numer / denom;
else
S = 0.0f;
T = 1.0f - S;
sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
T * (A01 * S + A11 * T + 2.0f * B1) + C;
le = 2;
}
}
}
}
/* Account for numerical round-off error */
if (sqrDist < FLT_EPSILON)
sqrDist = 0.0f;
{
float w[3], x[3], y[3], z[3];
copy_v3_v3(w, v0);
copy_v3_v3(x, e0);
mul_v3_fl(x, S);
copy_v3_v3(y, e1);
mul_v3_fl(y, T);
add_v3_v3v3(z, w, x);
add_v3_v3v3(z, z, y);
//sub_v3_v3v3(d, p, z);
copy_v3_v3(nearest, z);
//d = p - ( v0 + S * e0 + T * e1 );
}
*v = lv;
*e = le;
return sqrDist;
}
/*
* BVH from meshes callbacks
*/
/* Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_faces.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
static void mesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
MVert *vert = data->vert;
MFace *face = data->face + index;
const float *t0, *t1, *t2, *t3;
t0 = vert[face->v1].co;
t1 = vert[face->v2].co;
t2 = vert[face->v3].co;
t3 = face->v4 ? vert[face->v4].co : NULL;
do {
float nearest_tmp[3], dist_sq;
int vertex, edge;
dist_sq = nearest_point_in_tri_surface_squared(t0, t1, t2, co, &vertex, &edge, nearest_tmp);
if (dist_sq < nearest->dist_sq) {
nearest->index = index;
nearest->dist_sq = dist_sq;
copy_v3_v3(nearest->co, nearest_tmp);
normal_tri_v3(nearest->no, t0, t1, t2);
if (t1 == vert[face->v3].co)
nearest->flags |= BVH_ONQUAD;
}
t1 = t2;
t2 = t3;
t3 = NULL;
} while (t2);
}
/* 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)
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
BMEditMesh *em = data->em_evil;
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
const float *t0, *t1, *t2;
t0 = ltri[0]->v->co;
t1 = ltri[1]->v->co;
t2 = ltri[2]->v->co;
{
float nearest_tmp[3], dist_sq;
int vertex, edge;
dist_sq = nearest_point_in_tri_surface_squared(t0, t1, t2, co, &vertex, &edge, nearest_tmp);
if (dist_sq < nearest->dist_sq) {
nearest->index = index;
nearest->dist_sq = dist_sq;
copy_v3_v3(nearest->co, nearest_tmp);
normal_tri_v3(nearest->no, t0, t1, t2);
}
}
}
/* Callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_faces.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
static void mesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
MVert *vert = data->vert;
MFace *face = data->face + index;
const float *t0, *t1, *t2, *t3;
t0 = vert[face->v1].co;
t1 = vert[face->v2].co;
t2 = vert[face->v3].co;
t3 = face->v4 ? vert[face->v4].co : NULL;
do {
float dist;
if (data->sphere_radius == 0.0f)
dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
else
dist = sphereray_tri_intersection(ray, data->sphere_radius, hit->dist, t0, t1, t2);
if (dist >= 0 && dist < hit->dist) {
hit->index = index;
hit->dist = dist;
madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
normal_tri_v3(hit->no, t0, t1, t2);
if (t1 == vert[face->v3].co)
hit->flags |= BVH_ONQUAD;
}
t1 = t2;
t2 = t3;
t3 = NULL;
} while (t2);
}
/* 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)
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
BMEditMesh *em = data->em_evil;
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
const float *t0, *t1, *t2;
t0 = ltri[0]->v->co;
t1 = ltri[1]->v->co;
t2 = ltri[2]->v->co;
{
float dist;
if (data->sphere_radius == 0.0f)
dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
else
dist = sphereray_tri_intersection(ray, data->sphere_radius, hit->dist, t0, t1, t2);
if (dist >= 0 && dist < hit->dist) {
hit->index = index;
hit->dist = dist;
madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
normal_tri_v3(hit->no, t0, t1, t2);
}
}
}
/* Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_edges.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
static void mesh_edges_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
MVert *vert = data->vert;
MEdge *edge = data->edge + index;
float nearest_tmp[3], dist_sq;
const float *t0, *t1;
t0 = vert[edge->v1].co;
t1 = vert[edge->v2].co;
closest_to_line_segment_v3(nearest_tmp, co, t0, t1);
dist_sq = len_squared_v3v3(nearest_tmp, co);
if (dist_sq < nearest->dist_sq) {
nearest->index = index;
nearest->dist_sq = dist_sq;
copy_v3_v3(nearest->co, nearest_tmp);
sub_v3_v3v3(nearest->no, t0, t1);
normalize_v3(nearest->no);
}
}
/*
* BVH builders
*/
/* 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 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 faces 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 = NULL;
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;
}
/* Frees data allocated by a call to bvhtree_from_mesh_*. */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
if (data->tree) {
if (!data->cached)
BLI_bvhtree_free(data->tree);
if (data->vert_allocated) {
MEM_freeN(data->vert);
}
if (data->edge_allocated) {
MEM_freeN(data->edge);
}
if (data->face_allocated) {
MEM_freeN(data->face);
}
memset(data, 0, sizeof(*data));
}
}
/* BVHCache */
typedef struct BVHCacheItem {
int type;
BVHTree *tree;
} BVHCacheItem;
static void bvhcacheitem_set_if_match(void *_cached, void *_search)
{
BVHCacheItem *cached = (BVHCacheItem *)_cached;
BVHCacheItem *search = (BVHCacheItem *)_search;
if (search->type == cached->type) {
search->tree = cached->tree;
}
}
BVHTree *bvhcache_find(BVHCache *cache, int type)
{
BVHCacheItem item;
item.type = type;
item.tree = NULL;
BLI_linklist_apply(*cache, bvhcacheitem_set_if_match, &item);
return item.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);
}
void bvhcache_init(BVHCache *cache)
{
*cache = NULL;
}
static void bvhcacheitem_free(void *_item)
{
BVHCacheItem *item = (BVHCacheItem *)_item;
BLI_bvhtree_free(item->tree);
MEM_freeN(item);
}
void bvhcache_free(BVHCache *cache)
{
BLI_linklist_free(*cache, (LinkNodeFreeFP)bvhcacheitem_free);
*cache = NULL;
}