1697 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1697 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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.
 | 
						|
 */
 | 
						|
 | 
						|
/** \file
 | 
						|
 * \ingroup bke
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <math.h>
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
#include "DNA_mesh_types.h"
 | 
						|
#include "DNA_meshdata_types.h"
 | 
						|
 | 
						|
#include "BLI_utildefines.h"
 | 
						|
#include "BLI_linklist.h"
 | 
						|
#include "BLI_math.h"
 | 
						|
#include "BLI_threads.h"
 | 
						|
 | 
						|
#include "BKE_bvhutils.h"
 | 
						|
#include "BKE_editmesh.h"
 | 
						|
#include "BKE_mesh.h"
 | 
						|
#include "BKE_mesh_runtime.h"
 | 
						|
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
 | 
						|
static ThreadRWMutex cache_rwlock = BLI_RWLOCK_INITIALIZER;
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name Local Callbacks
 | 
						|
 * \{ */
 | 
						|
 | 
						|
/* 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;
 | 
						|
 | 
						|
#ifdef USE_KDOPBVH_WATERTIGHT
 | 
						|
  if (isect_ray_tri_watertight_v3(ray->origin, ray->isect_precalc, v0, v1, v2, &dist, NULL))
 | 
						|
#else
 | 
						|
  if (isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON))
 | 
						|
#endif
 | 
						|
  {
 | 
						|
    return dist;
 | 
						|
  }
 | 
						|
 | 
						|
  return FLT_MAX;
 | 
						|
}
 | 
						|
 | 
						|
float bvhtree_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 hit_point[3];
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * BVH from meshes callbacks
 | 
						|
 */
 | 
						|
 | 
						|
/* Callback to bvh tree nearest point. The tree must 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;
 | 
						|
  const MVert *vert = data->vert;
 | 
						|
  const 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;
 | 
						|
 | 
						|
    closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
 | 
						|
    dist_sq = len_squared_v3v3(co, 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);
 | 
						|
    }
 | 
						|
 | 
						|
    t1 = t2;
 | 
						|
    t2 = t3;
 | 
						|
    t3 = NULL;
 | 
						|
 | 
						|
  } while (t2);
 | 
						|
}
 | 
						|
/* copy of function above */
 | 
						|
static void mesh_looptri_nearest_point(void *userdata,
 | 
						|
                                       int index,
 | 
						|
                                       const float co[3],
 | 
						|
                                       BVHTreeNearest *nearest)
 | 
						|
{
 | 
						|
  const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
 | 
						|
  const MVert *vert = data->vert;
 | 
						|
  const MLoopTri *lt = &data->looptri[index];
 | 
						|
  const float *vtri_co[3] = {
 | 
						|
      vert[data->loop[lt->tri[0]].v].co,
 | 
						|
      vert[data->loop[lt->tri[1]].v].co,
 | 
						|
      vert[data->loop[lt->tri[2]].v].co,
 | 
						|
  };
 | 
						|
  float nearest_tmp[3], dist_sq;
 | 
						|
 | 
						|
  closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(vtri_co));
 | 
						|
  dist_sq = len_squared_v3v3(co, 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, UNPACK3(vtri_co));
 | 
						|
  }
 | 
						|
}
 | 
						|
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
 | 
						|
static void editmesh_looptri_nearest_point(void *userdata,
 | 
						|
                                           int index,
 | 
						|
                                           const float co[3],
 | 
						|
                                           BVHTreeNearest *nearest)
 | 
						|
{
 | 
						|
  const BVHTreeFromEditMesh *data = userdata;
 | 
						|
  BMEditMesh *em = data->em;
 | 
						|
  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;
 | 
						|
 | 
						|
    closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
 | 
						|
    dist_sq = len_squared_v3v3(co, 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 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;
 | 
						|
  const MVert *vert = data->vert;
 | 
						|
  const 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 (ray->radius == 0.0f) {
 | 
						|
      dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      dist = bvhtree_sphereray_tri_intersection(ray, ray->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);
 | 
						|
    }
 | 
						|
 | 
						|
    t1 = t2;
 | 
						|
    t2 = t3;
 | 
						|
    t3 = NULL;
 | 
						|
 | 
						|
  } while (t2);
 | 
						|
}
 | 
						|
/* copy of function above */
 | 
						|
static void mesh_looptri_spherecast(void *userdata,
 | 
						|
                                    int index,
 | 
						|
                                    const BVHTreeRay *ray,
 | 
						|
                                    BVHTreeRayHit *hit)
 | 
						|
{
 | 
						|
  const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
 | 
						|
  const MVert *vert = data->vert;
 | 
						|
  const MLoopTri *lt = &data->looptri[index];
 | 
						|
  const float *vtri_co[3] = {
 | 
						|
      vert[data->loop[lt->tri[0]].v].co,
 | 
						|
      vert[data->loop[lt->tri[1]].v].co,
 | 
						|
      vert[data->loop[lt->tri[2]].v].co,
 | 
						|
  };
 | 
						|
  float dist;
 | 
						|
 | 
						|
  if (ray->radius == 0.0f) {
 | 
						|
    dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, UNPACK3(vtri_co));
 | 
						|
  }
 | 
						|
 | 
						|
  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, UNPACK3(vtri_co));
 | 
						|
  }
 | 
						|
}
 | 
						|
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
 | 
						|
static void editmesh_looptri_spherecast(void *userdata,
 | 
						|
                                        int index,
 | 
						|
                                        const BVHTreeRay *ray,
 | 
						|
                                        BVHTreeRayHit *hit)
 | 
						|
{
 | 
						|
  const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
 | 
						|
  BMEditMesh *em = data->em;
 | 
						|
  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 (ray->radius == 0.0f) {
 | 
						|
      dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      dist = bvhtree_sphereray_tri_intersection(ray, ray->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 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;
 | 
						|
  const MVert *vert = data->vert;
 | 
						|
  const 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);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Helper, does all the point-spherecast work actually. */
 | 
						|
static void mesh_verts_spherecast_do(int index,
 | 
						|
                                     const float v[3],
 | 
						|
                                     const BVHTreeRay *ray,
 | 
						|
                                     BVHTreeRayHit *hit)
 | 
						|
{
 | 
						|
  float dist;
 | 
						|
  const float *r1;
 | 
						|
  float r2[3], i1[3];
 | 
						|
  r1 = ray->origin;
 | 
						|
  add_v3_v3v3(r2, r1, ray->direction);
 | 
						|
 | 
						|
  closest_to_line_segment_v3(i1, v, r1, r2);
 | 
						|
 | 
						|
  /* No hit if closest point is 'behind' the origin of the ray, or too far away from it. */
 | 
						|
  if ((dot_v3v3v3(r1, i1, r2) >= 0.0f) && ((dist = len_v3v3(r1, i1)) < hit->dist)) {
 | 
						|
    hit->index = index;
 | 
						|
    hit->dist = dist;
 | 
						|
    copy_v3_v3(hit->co, i1);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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)
 | 
						|
{
 | 
						|
  const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
 | 
						|
  const float *v = data->vert[index].co;
 | 
						|
 | 
						|
  mesh_verts_spherecast_do(index, v, ray, hit);
 | 
						|
}
 | 
						|
 | 
						|
/* Callback to bvh tree raycast. The tree must 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_spherecast(void *userdata,
 | 
						|
                                  int index,
 | 
						|
                                  const BVHTreeRay *ray,
 | 
						|
                                  BVHTreeRayHit *hit)
 | 
						|
{
 | 
						|
  const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
 | 
						|
  const MVert *vert = data->vert;
 | 
						|
  const MEdge *edge = &data->edge[index];
 | 
						|
 | 
						|
  const float radius_sq = SQUARE(ray->radius);
 | 
						|
  float dist;
 | 
						|
  const float *v1, *v2, *r1;
 | 
						|
  float r2[3], i1[3], i2[3];
 | 
						|
  v1 = vert[edge->v1].co;
 | 
						|
  v2 = vert[edge->v2].co;
 | 
						|
 | 
						|
  /* In case we get a zero-length edge, handle it as a point! */
 | 
						|
  if (equals_v3v3(v1, v2)) {
 | 
						|
    mesh_verts_spherecast_do(index, v1, ray, hit);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  r1 = ray->origin;
 | 
						|
  add_v3_v3v3(r2, r1, ray->direction);
 | 
						|
 | 
						|
  if (isect_line_line_v3(v1, v2, r1, r2, i1, i2)) {
 | 
						|
    /* No hit if intersection point is 'behind' the origin of the ray, or too far away from it. */
 | 
						|
    if ((dot_v3v3v3(r1, i2, r2) >= 0.0f) && ((dist = len_v3v3(r1, i2)) < hit->dist)) {
 | 
						|
      const float e_fac = line_point_factor_v3(i1, v1, v2);
 | 
						|
      if (e_fac < 0.0f) {
 | 
						|
        copy_v3_v3(i1, v1);
 | 
						|
      }
 | 
						|
      else if (e_fac > 1.0f) {
 | 
						|
        copy_v3_v3(i1, v2);
 | 
						|
      }
 | 
						|
      /* Ensure ray is really close enough from edge! */
 | 
						|
      if (len_squared_v3v3(i1, i2) <= radius_sq) {
 | 
						|
        hit->index = index;
 | 
						|
        hit->dist = dist;
 | 
						|
        copy_v3_v3(hit->co, i2);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/** \} */
 | 
						|
 | 
						|
/*
 | 
						|
 * BVH builders
 | 
						|
 */
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name Vertex Builder
 | 
						|
 * \{ */
 | 
						|
 | 
						|
static BVHTree *bvhtree_from_editmesh_verts_create_tree(float epsilon,
 | 
						|
                                                        int tree_type,
 | 
						|
                                                        int axis,
 | 
						|
                                                        BMEditMesh *em,
 | 
						|
                                                        const BLI_bitmap *verts_mask,
 | 
						|
                                                        int verts_num_active)
 | 
						|
{
 | 
						|
  BM_mesh_elem_table_ensure(em->bm, BM_VERT);
 | 
						|
  const int verts_num = em->bm->totvert;
 | 
						|
  if (verts_mask) {
 | 
						|
    BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    verts_num_active = verts_num;
 | 
						|
  }
 | 
						|
 | 
						|
  BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
 | 
						|
 | 
						|
  if (tree) {
 | 
						|
    for (int i = 0; i < verts_num; i++) {
 | 
						|
      if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      BMVert *eve = BM_vert_at_index(em->bm, i);
 | 
						|
      BLI_bvhtree_insert(tree, i, eve->co, 1);
 | 
						|
    }
 | 
						|
    BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
 | 
						|
    BLI_bvhtree_balance(tree);
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
 | 
						|
                                                    int tree_type,
 | 
						|
                                                    int axis,
 | 
						|
                                                    const MVert *vert,
 | 
						|
                                                    const int verts_num,
 | 
						|
                                                    const BLI_bitmap *verts_mask,
 | 
						|
                                                    int verts_num_active)
 | 
						|
{
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
 | 
						|
  if (verts_mask) {
 | 
						|
    BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    verts_num_active = verts_num;
 | 
						|
  }
 | 
						|
 | 
						|
  if (verts_num_active) {
 | 
						|
    tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
 | 
						|
 | 
						|
    if (tree) {
 | 
						|
      for (int i = 0; i < verts_num; i++) {
 | 
						|
        if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        BLI_bvhtree_insert(tree, i, vert[i].co, 1);
 | 
						|
      }
 | 
						|
      BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
 | 
						|
      BLI_bvhtree_balance(tree);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
static void bvhtree_from_mesh_verts_setup_data(BVHTreeFromMesh *data,
 | 
						|
                                               BVHTree *tree,
 | 
						|
                                               const bool is_cached,
 | 
						|
                                               const MVert *vert,
 | 
						|
                                               const bool vert_allocated)
 | 
						|
{
 | 
						|
  memset(data, 0, sizeof(*data));
 | 
						|
 | 
						|
  data->tree = tree;
 | 
						|
  data->cached = is_cached;
 | 
						|
 | 
						|
  /* 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 = mesh_verts_spherecast;
 | 
						|
 | 
						|
  data->vert = vert;
 | 
						|
  data->vert_allocated = vert_allocated;
 | 
						|
}
 | 
						|
 | 
						|
/* 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,
 | 
						|
                                        const int bvh_cache_type,
 | 
						|
                                        BVHCache **bvh_cache)
 | 
						|
{
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
 | 
						|
  if (bvh_cache) {
 | 
						|
    BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
 | 
						|
    data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
 | 
						|
    BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
 | 
						|
    if (data->cached == false) {
 | 
						|
      BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
 | 
						|
      data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
 | 
						|
      if (data->cached == false) {
 | 
						|
        tree = bvhtree_from_editmesh_verts_create_tree(
 | 
						|
            epsilon, tree_type, axis, em, verts_mask, verts_num_active);
 | 
						|
 | 
						|
        /* Save on cache for later use */
 | 
						|
        /* printf("BVHTree built and saved on cache\n"); */
 | 
						|
        bvhcache_insert(bvh_cache, tree, bvh_cache_type);
 | 
						|
        data->cached = true;
 | 
						|
      }
 | 
						|
      BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    tree = bvhtree_from_editmesh_verts_create_tree(
 | 
						|
        epsilon, tree_type, axis, em, 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->cached = bvh_cache != 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, 0, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * 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 verts_mask: if not null, true elements give which vert to add to BVH tree.
 | 
						|
 * \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,
 | 
						|
                                    const 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,
 | 
						|
                                    const int bvh_cache_type,
 | 
						|
                                    BVHCache **bvh_cache)
 | 
						|
{
 | 
						|
  bool in_cache = false;
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
  if (bvh_cache) {
 | 
						|
    BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
 | 
						|
    in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
    BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
    if (in_cache == false) {
 | 
						|
      BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
 | 
						|
      in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
      if (in_cache) {
 | 
						|
        BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (in_cache == false) {
 | 
						|
    tree = bvhtree_from_mesh_verts_create_tree(
 | 
						|
        epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
 | 
						|
 | 
						|
    if (bvh_cache) {
 | 
						|
      /* Save on cache for later use */
 | 
						|
      /* printf("BVHTree built and saved on cache\n"); */
 | 
						|
      bvhcache_insert(bvh_cache, tree, bvh_cache_type);
 | 
						|
      BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
      in_cache = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Setup BVHTreeFromMesh */
 | 
						|
  bvhtree_from_mesh_verts_setup_data(data, tree, in_cache, vert, vert_allocated);
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
/** \} */
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name Edge Builder
 | 
						|
 * \{ */
 | 
						|
 | 
						|
static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
 | 
						|
                                                        int tree_type,
 | 
						|
                                                        int axis,
 | 
						|
                                                        BMEditMesh *em,
 | 
						|
                                                        const BLI_bitmap *edges_mask,
 | 
						|
                                                        int edges_num_active)
 | 
						|
{
 | 
						|
  BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
 | 
						|
  const int edges_num = em->bm->totedge;
 | 
						|
 | 
						|
  if (edges_mask) {
 | 
						|
    BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    edges_num_active = edges_num;
 | 
						|
  }
 | 
						|
 | 
						|
  BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
 | 
						|
 | 
						|
  if (tree) {
 | 
						|
    int i;
 | 
						|
    BMIter iter;
 | 
						|
    BMEdge *eed;
 | 
						|
    BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
 | 
						|
      if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      float co[2][3];
 | 
						|
      copy_v3_v3(co[0], eed->v1->co);
 | 
						|
      copy_v3_v3(co[1], eed->v2->co);
 | 
						|
 | 
						|
      BLI_bvhtree_insert(tree, i, co[0], 2);
 | 
						|
    }
 | 
						|
    BLI_assert(BLI_bvhtree_get_len(tree) == edges_num_active);
 | 
						|
    BLI_bvhtree_balance(tree);
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
static BVHTree *bvhtree_from_mesh_edges_create_tree(const MVert *vert,
 | 
						|
                                                    const MEdge *edge,
 | 
						|
                                                    const int edge_num,
 | 
						|
                                                    const BLI_bitmap *edges_mask,
 | 
						|
                                                    int edges_num_active,
 | 
						|
                                                    float epsilon,
 | 
						|
                                                    int tree_type,
 | 
						|
                                                    int axis)
 | 
						|
{
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
 | 
						|
  if (edges_mask) {
 | 
						|
    BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    edges_num_active = edge_num;
 | 
						|
  }
 | 
						|
 | 
						|
  if (edges_num_active) {
 | 
						|
    /* Create a bvh-tree of the given target */
 | 
						|
    tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
 | 
						|
    if (tree) {
 | 
						|
      for (int i = 0; i < edge_num; i++) {
 | 
						|
        if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        float co[2][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);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
static void bvhtree_from_mesh_edges_setup_data(BVHTreeFromMesh *data,
 | 
						|
                                               BVHTree *tree,
 | 
						|
                                               const bool is_cached,
 | 
						|
                                               const MVert *vert,
 | 
						|
                                               const bool vert_allocated,
 | 
						|
                                               const MEdge *edge,
 | 
						|
                                               const bool edge_allocated)
 | 
						|
{
 | 
						|
  memset(data, 0, sizeof(*data));
 | 
						|
 | 
						|
  data->tree = tree;
 | 
						|
 | 
						|
  data->cached = is_cached;
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/* Builds a bvh tree where nodes are the edges of the given em */
 | 
						|
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
 | 
						|
                                        BMEditMesh *em,
 | 
						|
                                        const BLI_bitmap *edges_mask,
 | 
						|
                                        int edges_num_active,
 | 
						|
                                        float epsilon,
 | 
						|
                                        int tree_type,
 | 
						|
                                        int axis,
 | 
						|
                                        const int bvh_cache_type,
 | 
						|
                                        BVHCache **bvh_cache)
 | 
						|
{
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
 | 
						|
  if (bvh_cache) {
 | 
						|
    BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
 | 
						|
    data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
 | 
						|
    BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
 | 
						|
    if (data->cached == false) {
 | 
						|
      BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
 | 
						|
      data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
 | 
						|
      if (data->cached == false) {
 | 
						|
        tree = bvhtree_from_editmesh_edges_create_tree(
 | 
						|
            epsilon, tree_type, axis, em, edges_mask, edges_num_active);
 | 
						|
 | 
						|
        /* Save on cache for later use */
 | 
						|
        /* printf("BVHTree built and saved on cache\n"); */
 | 
						|
        bvhcache_insert(bvh_cache, tree, bvh_cache_type);
 | 
						|
        data->cached = true;
 | 
						|
      }
 | 
						|
      BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    tree = bvhtree_from_editmesh_edges_create_tree(
 | 
						|
        epsilon, tree_type, axis, em, edges_mask, edges_num_active);
 | 
						|
  }
 | 
						|
 | 
						|
  if (tree) {
 | 
						|
    memset(data, 0, sizeof(*data));
 | 
						|
    data->tree = tree;
 | 
						|
    data->em = em;
 | 
						|
    data->nearest_callback = NULL; /* TODO */
 | 
						|
    data->raycast_callback = NULL; /* TODO */
 | 
						|
    data->cached = bvh_cache != NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
BVHTree *bvhtree_from_editmesh_edges(
 | 
						|
    BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
 | 
						|
{
 | 
						|
  return bvhtree_from_editmesh_edges_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Builds a bvh tree where nodes are the given edges .
 | 
						|
 * \param vert, vert_allocated: if true, elem freeing will be done when freeing data.
 | 
						|
 * \param edge, edge_allocated: if true, elem freeing will be done when freeing data.
 | 
						|
 * \param edges_mask: if not null, true elements give which vert to add to BVH tree.
 | 
						|
 * \param edges_num_active: if >= 0, number of active edges to add to BVH tree
 | 
						|
 * (else will be computed from mask).
 | 
						|
 */
 | 
						|
BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
 | 
						|
                                    const MVert *vert,
 | 
						|
                                    const bool vert_allocated,
 | 
						|
                                    const MEdge *edge,
 | 
						|
                                    const int edges_num,
 | 
						|
                                    const bool edge_allocated,
 | 
						|
                                    const BLI_bitmap *edges_mask,
 | 
						|
                                    int edges_num_active,
 | 
						|
                                    float epsilon,
 | 
						|
                                    int tree_type,
 | 
						|
                                    int axis,
 | 
						|
                                    const int bvh_cache_type,
 | 
						|
                                    BVHCache **bvh_cache)
 | 
						|
{
 | 
						|
  bool in_cache = false;
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
  if (bvh_cache) {
 | 
						|
    BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
 | 
						|
    in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
    BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
    if (in_cache == false) {
 | 
						|
      BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
 | 
						|
      in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
      if (in_cache) {
 | 
						|
        BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (in_cache == false) {
 | 
						|
    tree = bvhtree_from_mesh_edges_create_tree(
 | 
						|
        vert, edge, edges_num, edges_mask, edges_num_active, epsilon, tree_type, axis);
 | 
						|
 | 
						|
    if (bvh_cache) {
 | 
						|
      /* Save on cache for later use */
 | 
						|
      /* printf("BVHTree built and saved on cache\n"); */
 | 
						|
      bvhcache_insert(bvh_cache, tree, bvh_cache_type);
 | 
						|
      BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
      in_cache = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Setup BVHTreeFromMesh */
 | 
						|
  bvhtree_from_mesh_edges_setup_data(
 | 
						|
      data, tree, in_cache, vert, vert_allocated, edge, edge_allocated);
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
/** \} */
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name Tessellated Face Builder
 | 
						|
 * \{ */
 | 
						|
 | 
						|
static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
 | 
						|
                                                    int tree_type,
 | 
						|
                                                    int axis,
 | 
						|
                                                    const MVert *vert,
 | 
						|
                                                    const MFace *face,
 | 
						|
                                                    const int faces_num,
 | 
						|
                                                    const BLI_bitmap *faces_mask,
 | 
						|
                                                    int faces_num_active)
 | 
						|
{
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
  int i;
 | 
						|
 | 
						|
  if (faces_num) {
 | 
						|
    if (faces_mask) {
 | 
						|
      BLI_assert(IN_RANGE_INCL(faces_num_active, 0, faces_num));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      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(faces_num_active, epsilon, tree_type, axis);
 | 
						|
    if (tree) {
 | 
						|
      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;
 | 
						|
          }
 | 
						|
 | 
						|
          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_assert(BLI_bvhtree_get_len(tree) == faces_num_active);
 | 
						|
      BLI_bvhtree_balance(tree);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
static void bvhtree_from_mesh_faces_setup_data(BVHTreeFromMesh *data,
 | 
						|
                                               BVHTree *tree,
 | 
						|
                                               const bool is_cached,
 | 
						|
                                               const MVert *vert,
 | 
						|
                                               const bool vert_allocated,
 | 
						|
                                               const MFace *face,
 | 
						|
                                               const bool face_allocated)
 | 
						|
{
 | 
						|
  memset(data, 0, sizeof(*data));
 | 
						|
 | 
						|
  data->tree = tree;
 | 
						|
  data->cached = is_cached;
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Builds a bvh tree where nodes are the given tessellated faces
 | 
						|
 * (note: does not copy given mfaces!).
 | 
						|
 * \param vert_allocated: if true, vert freeing will be done when freeing data.
 | 
						|
 * \param face_allocated: if true, face freeing will be done when freeing data.
 | 
						|
 * \param faces_mask: if not null, true elements give which faces to add to BVH tree.
 | 
						|
 * \param faces_num_active: if >= 0, number of active faces to add to BVH tree
 | 
						|
 * (else will be computed from mask).
 | 
						|
 */
 | 
						|
BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
 | 
						|
                                    const MVert *vert,
 | 
						|
                                    const bool vert_allocated,
 | 
						|
                                    const MFace *face,
 | 
						|
                                    const int numFaces,
 | 
						|
                                    const bool face_allocated,
 | 
						|
                                    const BLI_bitmap *faces_mask,
 | 
						|
                                    int faces_num_active,
 | 
						|
                                    float epsilon,
 | 
						|
                                    int tree_type,
 | 
						|
                                    int axis,
 | 
						|
                                    const int bvh_cache_type,
 | 
						|
                                    BVHCache **bvh_cache)
 | 
						|
{
 | 
						|
  bool in_cache = false;
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
  if (bvh_cache) {
 | 
						|
    BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
 | 
						|
    in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
    BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
    if (in_cache == false) {
 | 
						|
      BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
 | 
						|
      in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
      if (in_cache) {
 | 
						|
        BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (in_cache == false) {
 | 
						|
    tree = bvhtree_from_mesh_faces_create_tree(
 | 
						|
        epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
 | 
						|
 | 
						|
    if (bvh_cache) {
 | 
						|
      /* Save on cache for later use */
 | 
						|
      /* printf("BVHTree built and saved on cache\n"); */
 | 
						|
      bvhcache_insert(bvh_cache, tree, bvh_cache_type);
 | 
						|
      BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
      in_cache = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Setup BVHTreeFromMesh */
 | 
						|
  bvhtree_from_mesh_faces_setup_data(
 | 
						|
      data, tree, in_cache, vert, vert_allocated, face, face_allocated);
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
/** \} */
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name LoopTri Face Builder
 | 
						|
 * \{ */
 | 
						|
 | 
						|
static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
 | 
						|
                                                          int tree_type,
 | 
						|
                                                          int axis,
 | 
						|
                                                          BMEditMesh *em,
 | 
						|
                                                          const BLI_bitmap *looptri_mask,
 | 
						|
                                                          int looptri_num_active)
 | 
						|
{
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
  const int looptri_num = em->tottri;
 | 
						|
 | 
						|
  if (looptri_num) {
 | 
						|
    if (looptri_mask) {
 | 
						|
      BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      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) {
 | 
						|
      const struct BMLoop *(*looptris)[3] = (void *)em->looptris;
 | 
						|
 | 
						|
      /* 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 (int i = 0; i < looptri_num; i++) {
 | 
						|
        const BMLoop **ltri = looptris[i];
 | 
						|
        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.*/
 | 
						|
          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);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
 | 
						|
      BLI_bvhtree_balance(tree);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
  if (looptri_mask) {
 | 
						|
    BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    looptri_num_active = looptri_num;
 | 
						|
  }
 | 
						|
 | 
						|
  if (looptri_num_active) {
 | 
						|
    /* 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 (int 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_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
 | 
						|
      BLI_bvhtree_balance(tree);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
static void bvhtree_from_mesh_looptri_setup_data(BVHTreeFromMesh *data,
 | 
						|
                                                 BVHTree *tree,
 | 
						|
                                                 const bool is_cached,
 | 
						|
                                                 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->tree = tree;
 | 
						|
  data->cached = is_cached;
 | 
						|
 | 
						|
  data->nearest_callback = mesh_looptri_nearest_point;
 | 
						|
  data->raycast_callback = mesh_looptri_spherecast;
 | 
						|
 | 
						|
  data->vert = vert;
 | 
						|
  data->vert_allocated = vert_allocated;
 | 
						|
  data->loop = mloop;
 | 
						|
  data->loop_allocated = loop_allocated;
 | 
						|
  data->looptri = looptri;
 | 
						|
  data->looptri_allocated = looptri_allocated;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * 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,
 | 
						|
                                          const int bvh_cache_type,
 | 
						|
                                          BVHCache **bvh_cache)
 | 
						|
{
 | 
						|
  /* BMESH specific check that we have tessfaces,
 | 
						|
   * we _could_ tessellate here but rather not - campbell */
 | 
						|
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
  if (bvh_cache) {
 | 
						|
    BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
 | 
						|
    bool in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
    BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
    if (in_cache == false) {
 | 
						|
      BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
 | 
						|
      in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
      if (in_cache == false) {
 | 
						|
        tree = bvhtree_from_editmesh_looptri_create_tree(
 | 
						|
            epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
 | 
						|
 | 
						|
        /* Save on cache for later use */
 | 
						|
        /* printf("BVHTree built and saved on cache\n"); */
 | 
						|
        bvhcache_insert(bvh_cache, tree, bvh_cache_type);
 | 
						|
      }
 | 
						|
      BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    tree = bvhtree_from_editmesh_looptri_create_tree(
 | 
						|
        epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
 | 
						|
  }
 | 
						|
 | 
						|
  if (tree) {
 | 
						|
    data->tree = tree;
 | 
						|
    data->nearest_callback = editmesh_looptri_nearest_point;
 | 
						|
    data->raycast_callback = editmesh_looptri_spherecast;
 | 
						|
    data->em = em;
 | 
						|
    data->cached = bvh_cache != NULL;
 | 
						|
  }
 | 
						|
  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, 0, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * 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_ex
 | 
						|
 */
 | 
						|
BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
 | 
						|
                                      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,
 | 
						|
                                      const BLI_bitmap *looptri_mask,
 | 
						|
                                      int looptri_num_active,
 | 
						|
                                      float epsilon,
 | 
						|
                                      int tree_type,
 | 
						|
                                      int axis,
 | 
						|
                                      const int bvh_cache_type,
 | 
						|
                                      BVHCache **bvh_cache)
 | 
						|
{
 | 
						|
  bool in_cache = false;
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
  if (bvh_cache) {
 | 
						|
    BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
 | 
						|
    in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
    BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
    if (in_cache == false) {
 | 
						|
      BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
 | 
						|
      in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
      if (in_cache) {
 | 
						|
        BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (in_cache == false) {
 | 
						|
    /* Setup BVHTreeFromMesh */
 | 
						|
    tree = bvhtree_from_mesh_looptri_create_tree(epsilon,
 | 
						|
                                                 tree_type,
 | 
						|
                                                 axis,
 | 
						|
                                                 vert,
 | 
						|
                                                 mloop,
 | 
						|
                                                 looptri,
 | 
						|
                                                 looptri_num,
 | 
						|
                                                 looptri_mask,
 | 
						|
                                                 looptri_num_active);
 | 
						|
 | 
						|
    if (bvh_cache) {
 | 
						|
      bvhcache_insert(bvh_cache, tree, bvh_cache_type);
 | 
						|
      BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
      in_cache = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Setup BVHTreeFromMesh */
 | 
						|
  bvhtree_from_mesh_looptri_setup_data(data,
 | 
						|
                                       tree,
 | 
						|
                                       in_cache,
 | 
						|
                                       vert,
 | 
						|
                                       vert_allocated,
 | 
						|
                                       mloop,
 | 
						|
                                       loop_allocated,
 | 
						|
                                       looptri,
 | 
						|
                                       looptri_allocated);
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
static BLI_bitmap *loose_verts_map_get(const MEdge *medge,
 | 
						|
                                       int edges_num,
 | 
						|
                                       const MVert *UNUSED(mvert),
 | 
						|
                                       int verts_num,
 | 
						|
                                       int *r_loose_vert_num)
 | 
						|
{
 | 
						|
  BLI_bitmap *loose_verts_mask = BLI_BITMAP_NEW(verts_num, __func__);
 | 
						|
  BLI_bitmap_set_all(loose_verts_mask, true, verts_num);
 | 
						|
 | 
						|
  const MEdge *e = medge;
 | 
						|
  int num_linked_verts = 0;
 | 
						|
  for (; edges_num--; e++) {
 | 
						|
    if (BLI_BITMAP_TEST(loose_verts_mask, e->v1)) {
 | 
						|
      BLI_BITMAP_DISABLE(loose_verts_mask, e->v1);
 | 
						|
      num_linked_verts++;
 | 
						|
    }
 | 
						|
    if (BLI_BITMAP_TEST(loose_verts_mask, e->v2)) {
 | 
						|
      BLI_BITMAP_DISABLE(loose_verts_mask, e->v2);
 | 
						|
      num_linked_verts++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  *r_loose_vert_num = verts_num - num_linked_verts;
 | 
						|
 | 
						|
  return loose_verts_mask;
 | 
						|
}
 | 
						|
 | 
						|
static BLI_bitmap *loose_edges_map_get(const MEdge *medge,
 | 
						|
                                       const int edges_len,
 | 
						|
                                       int *r_loose_edge_len)
 | 
						|
{
 | 
						|
  BLI_bitmap *loose_edges_mask = BLI_BITMAP_NEW(edges_len, __func__);
 | 
						|
 | 
						|
  int loose_edges_len = 0;
 | 
						|
  const MEdge *e = medge;
 | 
						|
  for (int i = 0; i < edges_len; i++, e++) {
 | 
						|
    if (e->flag & ME_LOOSEEDGE) {
 | 
						|
      BLI_BITMAP_ENABLE(loose_edges_mask, i);
 | 
						|
      loose_edges_len++;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      BLI_BITMAP_DISABLE(loose_edges_mask, i);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  *r_loose_edge_len = loose_edges_len;
 | 
						|
 | 
						|
  return loose_edges_mask;
 | 
						|
}
 | 
						|
 | 
						|
static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly,
 | 
						|
                                             const int looptri_len,
 | 
						|
                                             int *r_looptri_active_len)
 | 
						|
{
 | 
						|
  BLI_bitmap *looptri_mask = BLI_BITMAP_NEW(looptri_len, __func__);
 | 
						|
 | 
						|
  int looptri_no_hidden_len = 0;
 | 
						|
  int looptri_iter = 0;
 | 
						|
  const MPoly *mp = mpoly;
 | 
						|
  while (looptri_iter != looptri_len) {
 | 
						|
    int mp_totlooptri = mp->totloop - 2;
 | 
						|
    if (mp->flag & ME_HIDE) {
 | 
						|
      looptri_iter += mp_totlooptri;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      while (mp_totlooptri--) {
 | 
						|
        BLI_BITMAP_ENABLE(looptri_mask, looptri_iter);
 | 
						|
        looptri_iter++;
 | 
						|
        looptri_no_hidden_len++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    mp++;
 | 
						|
  }
 | 
						|
 | 
						|
  *r_looptri_active_len = looptri_no_hidden_len;
 | 
						|
 | 
						|
  return looptri_mask;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Builds or queries a bvhcache for the cache bvhtree of the request type.
 | 
						|
 */
 | 
						|
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
 | 
						|
                                   struct Mesh *mesh,
 | 
						|
                                   const int bvh_cache_type,
 | 
						|
                                   const int tree_type)
 | 
						|
{
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
  BVHCache **bvh_cache = &mesh->runtime.bvh_cache;
 | 
						|
 | 
						|
  BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
 | 
						|
  bool is_cached = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
  BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
 | 
						|
  if (is_cached && tree == NULL) {
 | 
						|
    memset(data, 0, sizeof(*data));
 | 
						|
    return tree;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (bvh_cache_type) {
 | 
						|
    case BVHTREE_FROM_VERTS:
 | 
						|
    case BVHTREE_FROM_LOOSEVERTS:
 | 
						|
      if (is_cached == false) {
 | 
						|
        BLI_bitmap *loose_verts_mask = NULL;
 | 
						|
        int loose_vert_len = -1;
 | 
						|
        int verts_len = mesh->totvert;
 | 
						|
 | 
						|
        if (bvh_cache_type == BVHTREE_FROM_LOOSEVERTS) {
 | 
						|
          loose_verts_mask = loose_verts_map_get(
 | 
						|
              mesh->medge, mesh->totedge, mesh->mvert, verts_len, &loose_vert_len);
 | 
						|
        }
 | 
						|
 | 
						|
        /* TODO: a global mutex lock held during the expensive operation of
 | 
						|
         * building the BVH tree is really bad for performance. */
 | 
						|
        tree = bvhtree_from_mesh_verts_ex(data,
 | 
						|
                                          mesh->mvert,
 | 
						|
                                          verts_len,
 | 
						|
                                          false,
 | 
						|
                                          loose_verts_mask,
 | 
						|
                                          loose_vert_len,
 | 
						|
                                          0.0f,
 | 
						|
                                          tree_type,
 | 
						|
                                          6,
 | 
						|
                                          bvh_cache_type,
 | 
						|
                                          bvh_cache);
 | 
						|
 | 
						|
        if (loose_verts_mask != NULL) {
 | 
						|
          MEM_freeN(loose_verts_mask);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        /* Setup BVHTreeFromMesh */
 | 
						|
        bvhtree_from_mesh_verts_setup_data(data, tree, true, mesh->mvert, false);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case BVHTREE_FROM_EDGES:
 | 
						|
    case BVHTREE_FROM_LOOSEEDGES:
 | 
						|
      if (is_cached == false) {
 | 
						|
        BLI_bitmap *loose_edges_mask = NULL;
 | 
						|
        int loose_edges_len = -1;
 | 
						|
        int edges_len = mesh->totedge;
 | 
						|
 | 
						|
        if (bvh_cache_type == BVHTREE_FROM_LOOSEEDGES) {
 | 
						|
          loose_edges_mask = loose_edges_map_get(mesh->medge, edges_len, &loose_edges_len);
 | 
						|
        }
 | 
						|
 | 
						|
        tree = bvhtree_from_mesh_edges_ex(data,
 | 
						|
                                          mesh->mvert,
 | 
						|
                                          false,
 | 
						|
                                          mesh->medge,
 | 
						|
                                          edges_len,
 | 
						|
                                          false,
 | 
						|
                                          loose_edges_mask,
 | 
						|
                                          loose_edges_len,
 | 
						|
                                          0.0,
 | 
						|
                                          tree_type,
 | 
						|
                                          6,
 | 
						|
                                          bvh_cache_type,
 | 
						|
                                          bvh_cache);
 | 
						|
 | 
						|
        if (loose_edges_mask != NULL) {
 | 
						|
          MEM_freeN(loose_edges_mask);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        /* Setup BVHTreeFromMesh */
 | 
						|
        bvhtree_from_mesh_edges_setup_data(
 | 
						|
            data, tree, true, mesh->mvert, false, mesh->medge, false);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case BVHTREE_FROM_FACES:
 | 
						|
      if (is_cached == false) {
 | 
						|
        int num_faces = mesh->totface;
 | 
						|
        BLI_assert(!(num_faces == 0 && mesh->totpoly != 0));
 | 
						|
 | 
						|
        tree = bvhtree_from_mesh_faces_ex(data,
 | 
						|
                                          mesh->mvert,
 | 
						|
                                          false,
 | 
						|
                                          mesh->mface,
 | 
						|
                                          num_faces,
 | 
						|
                                          false,
 | 
						|
                                          NULL,
 | 
						|
                                          -1,
 | 
						|
                                          0.0,
 | 
						|
                                          tree_type,
 | 
						|
                                          6,
 | 
						|
                                          bvh_cache_type,
 | 
						|
                                          bvh_cache);
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        /* Setup BVHTreeFromMesh */
 | 
						|
        bvhtree_from_mesh_faces_setup_data(
 | 
						|
            data, tree, true, mesh->mvert, false, mesh->mface, false);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case BVHTREE_FROM_LOOPTRI:
 | 
						|
    case BVHTREE_FROM_LOOPTRI_NO_HIDDEN:
 | 
						|
      if (is_cached == false) {
 | 
						|
        const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
 | 
						|
        int looptri_len = BKE_mesh_runtime_looptri_len(mesh);
 | 
						|
 | 
						|
        int looptri_mask_active_len = -1;
 | 
						|
        BLI_bitmap *looptri_mask = NULL;
 | 
						|
        if (bvh_cache_type == BVHTREE_FROM_LOOPTRI_NO_HIDDEN) {
 | 
						|
          looptri_mask = looptri_no_hidden_map_get(
 | 
						|
              mesh->mpoly, looptri_len, &looptri_mask_active_len);
 | 
						|
        }
 | 
						|
 | 
						|
        tree = bvhtree_from_mesh_looptri_ex(data,
 | 
						|
                                            mesh->mvert,
 | 
						|
                                            false,
 | 
						|
                                            mesh->mloop,
 | 
						|
                                            false,
 | 
						|
                                            mlooptri,
 | 
						|
                                            looptri_len,
 | 
						|
                                            false,
 | 
						|
                                            looptri_mask,
 | 
						|
                                            looptri_mask_active_len,
 | 
						|
                                            0.0,
 | 
						|
                                            tree_type,
 | 
						|
                                            6,
 | 
						|
                                            bvh_cache_type,
 | 
						|
                                            bvh_cache);
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        /* Setup BVHTreeFromMesh */
 | 
						|
        const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
 | 
						|
        bvhtree_from_mesh_looptri_setup_data(
 | 
						|
            data, tree, true, mesh->mvert, false, mesh->mloop, false, mlooptri, false);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case BVHTREE_FROM_EM_VERTS:
 | 
						|
    case BVHTREE_FROM_EM_EDGES:
 | 
						|
    case BVHTREE_FROM_EM_LOOPTRI:
 | 
						|
      BLI_assert(false);
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (data->tree != NULL) {
 | 
						|
#ifdef DEBUG
 | 
						|
    if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) {
 | 
						|
      printf("tree_type %d obtained instead of %d\n",
 | 
						|
             BLI_bvhtree_get_tree_type(data->tree),
 | 
						|
             tree_type);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    BLI_assert(data->cached);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    free_bvhtree_from_mesh(data);
 | 
						|
    memset(data, 0, sizeof(*data));
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Builds or queries a bvhcache for the cache bvhtree of the request type.
 | 
						|
 */
 | 
						|
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
 | 
						|
                                       struct BMEditMesh *em,
 | 
						|
                                       const int tree_type,
 | 
						|
                                       const int bvh_cache_type,
 | 
						|
                                       BVHCache **bvh_cache)
 | 
						|
{
 | 
						|
  BVHTree *tree = NULL;
 | 
						|
  bool is_cached = false;
 | 
						|
 | 
						|
  memset(data, 0, sizeof(*data));
 | 
						|
 | 
						|
  if (bvh_cache) {
 | 
						|
    BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
 | 
						|
    is_cached = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
 | 
						|
    BLI_rw_mutex_unlock(&cache_rwlock);
 | 
						|
 | 
						|
    if (is_cached && tree == NULL) {
 | 
						|
      return tree;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  data->tree = tree;
 | 
						|
  data->em = em;
 | 
						|
  data->cached = is_cached;
 | 
						|
 | 
						|
  switch (bvh_cache_type) {
 | 
						|
    case BVHTREE_FROM_EM_VERTS:
 | 
						|
      if (is_cached == false) {
 | 
						|
        tree = bvhtree_from_editmesh_verts_ex(
 | 
						|
            data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        data->nearest_callback = NULL;
 | 
						|
        data->raycast_callback = editmesh_verts_spherecast;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case BVHTREE_FROM_EM_EDGES:
 | 
						|
      if (is_cached == false) {
 | 
						|
        tree = bvhtree_from_editmesh_edges_ex(
 | 
						|
            data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        /* Setup BVHTreeFromMesh */
 | 
						|
        data->nearest_callback = NULL; /* TODO */
 | 
						|
        data->raycast_callback = NULL; /* TODO */
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case BVHTREE_FROM_EM_LOOPTRI:
 | 
						|
      if (is_cached == false) {
 | 
						|
        tree = bvhtree_from_editmesh_looptri_ex(
 | 
						|
            data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        /* Setup BVHTreeFromMesh */
 | 
						|
        data->nearest_callback = editmesh_looptri_nearest_point;
 | 
						|
        data->raycast_callback = editmesh_looptri_spherecast;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case BVHTREE_FROM_VERTS:
 | 
						|
    case BVHTREE_FROM_EDGES:
 | 
						|
    case BVHTREE_FROM_FACES:
 | 
						|
    case BVHTREE_FROM_LOOPTRI:
 | 
						|
    case BVHTREE_FROM_LOOPTRI_NO_HIDDEN:
 | 
						|
    case BVHTREE_FROM_LOOSEVERTS:
 | 
						|
    case BVHTREE_FROM_LOOSEEDGES:
 | 
						|
      BLI_assert(false);
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (data->tree != NULL) {
 | 
						|
#ifdef DEBUG
 | 
						|
    if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) {
 | 
						|
      printf("tree_type %d obtained instead of %d\n",
 | 
						|
             BLI_bvhtree_get_tree_type(data->tree),
 | 
						|
             tree_type);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    BLI_assert(data->cached);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    free_bvhtree_from_editmesh(data);
 | 
						|
    memset(data, 0, sizeof(*data));
 | 
						|
  }
 | 
						|
 | 
						|
  return tree;
 | 
						|
}
 | 
						|
 | 
						|
/** \} */
 | 
						|
 | 
						|
/* Frees data allocated by a call to bvhtree_from_editmesh_*. */
 | 
						|
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
 | 
						|
{
 | 
						|
  if (data->tree) {
 | 
						|
    if (!data->cached) {
 | 
						|
      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)
 | 
						|
{
 | 
						|
  if (data->tree && !data->cached) {
 | 
						|
    BLI_bvhtree_free(data->tree);
 | 
						|
  }
 | 
						|
 | 
						|
  if (data->vert_allocated) {
 | 
						|
    MEM_freeN((void *)data->vert);
 | 
						|
  }
 | 
						|
  if (data->edge_allocated) {
 | 
						|
    MEM_freeN((void *)data->edge);
 | 
						|
  }
 | 
						|
  if (data->face_allocated) {
 | 
						|
    MEM_freeN((void *)data->face);
 | 
						|
  }
 | 
						|
  if (data->loop_allocated) {
 | 
						|
    MEM_freeN((void *)data->loop);
 | 
						|
  }
 | 
						|
  if (data->looptri_allocated) {
 | 
						|
    MEM_freeN((void *)data->looptri);
 | 
						|
  }
 | 
						|
 | 
						|
  memset(data, 0, sizeof(*data));
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name BVHCache
 | 
						|
 * \{ */
 | 
						|
 | 
						|
typedef struct BVHCacheItem {
 | 
						|
  int type;
 | 
						|
  BVHTree *tree;
 | 
						|
 | 
						|
} BVHCacheItem;
 | 
						|
 | 
						|
/**
 | 
						|
 * Queries a bvhcache for the cache bvhtree of the request type
 | 
						|
 */
 | 
						|
bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree)
 | 
						|
{
 | 
						|
  while (cache) {
 | 
						|
    const BVHCacheItem *item = cache->link;
 | 
						|
    if (item->type == type) {
 | 
						|
      *r_tree = item->tree;
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    cache = cache->next;
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
 | 
						|
{
 | 
						|
  while (cache) {
 | 
						|
    const BVHCacheItem *item = cache->link;
 | 
						|
    if (item->tree == tree) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    cache = cache->next;
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Inserts a BVHTree of the given type under the cache
 | 
						|
 * After that the caller no longer needs to worry when to free the BVHTree
 | 
						|
 * as that will be done when the cache is freed.
 | 
						|
 *
 | 
						|
 * A call to this assumes that there was no previous cached tree of the given type
 | 
						|
 * \warning The #BVHTree can be NULL.
 | 
						|
 */
 | 
						|
void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
 | 
						|
{
 | 
						|
  BVHCacheItem *item = NULL;
 | 
						|
 | 
						|
  BLI_assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false);
 | 
						|
 | 
						|
  item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
 | 
						|
 | 
						|
  item->type = type;
 | 
						|
  item->tree = tree;
 | 
						|
 | 
						|
  BLI_linklist_prepend(cache_p, item);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * frees a bvhcache
 | 
						|
 */
 | 
						|
static void bvhcacheitem_free(void *_item)
 | 
						|
{
 | 
						|
  BVHCacheItem *item = (BVHCacheItem *)_item;
 | 
						|
 | 
						|
  BLI_bvhtree_free(item->tree);
 | 
						|
  MEM_freeN(item);
 | 
						|
}
 | 
						|
 | 
						|
void bvhcache_free(BVHCache **cache_p)
 | 
						|
{
 | 
						|
  BLI_linklist_free(*cache_p, (LinkNodeFreeFP)bvhcacheitem_free);
 | 
						|
  *cache_p = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/** \} */
 |