1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 */
23
24 #include <math.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "DNA_mesh_types.h"
29 #include "DNA_meshdata_types.h"
30
31 #include "BLI_linklist.h"
32 #include "BLI_math.h"
33 #include "BLI_threads.h"
34 #include "BLI_utildefines.h"
35
36 #include "BKE_bvhutils.h"
37 #include "BKE_editmesh.h"
38 #include "BKE_mesh.h"
39 #include "BKE_mesh_runtime.h"
40
41 #include "MEM_guardedalloc.h"
42
43 /* -------------------------------------------------------------------- */
44 /** \name BVHCache
45 * \{ */
46
47 typedef struct BVHCacheItem {
48 bool is_filled;
49 BVHTree *tree;
50 } BVHCacheItem;
51
52 typedef struct BVHCache {
53 BVHCacheItem items[BVHTREE_MAX_ITEM];
54 ThreadMutex mutex;
55 } BVHCache;
56
57 /**
58 * Queries a bvhcache for the cache bvhtree of the request type
59 *
60 * When the `r_locked` is filled and the tree could not be found the caches mutex will be
61 * locked. This mutex can be unlocked by calling `bvhcache_unlock`.
62 *
63 * When `r_locked` is used the `mesh_eval_mutex` must contain the `Mesh_Runtime.eval_mutex`.
64 */
bvhcache_find(BVHCache ** bvh_cache_p,BVHCacheType type,BVHTree ** r_tree,bool * r_locked,ThreadMutex * mesh_eval_mutex)65 static bool bvhcache_find(BVHCache **bvh_cache_p,
66 BVHCacheType type,
67 BVHTree **r_tree,
68 bool *r_locked,
69 ThreadMutex *mesh_eval_mutex)
70 {
71 bool do_lock = r_locked;
72 if (r_locked) {
73 *r_locked = false;
74 }
75 if (*bvh_cache_p == NULL) {
76 if (!do_lock) {
77 /* Cache does not exist and no lock is requested. */
78 return false;
79 }
80 /* Lazy initialization of the bvh_cache using the `mesh_eval_mutex`. */
81 BLI_mutex_lock(mesh_eval_mutex);
82 if (*bvh_cache_p == NULL) {
83 *bvh_cache_p = bvhcache_init();
84 }
85 BLI_mutex_unlock(mesh_eval_mutex);
86 }
87 BVHCache *bvh_cache = *bvh_cache_p;
88
89 if (bvh_cache->items[type].is_filled) {
90 *r_tree = bvh_cache->items[type].tree;
91 return true;
92 }
93 if (do_lock) {
94 BLI_mutex_lock(&bvh_cache->mutex);
95 bool in_cache = bvhcache_find(bvh_cache_p, type, r_tree, NULL, NULL);
96 if (in_cache) {
97 BLI_mutex_unlock(&bvh_cache->mutex);
98 return in_cache;
99 }
100 *r_locked = true;
101 }
102 return false;
103 }
104
bvhcache_unlock(BVHCache * bvh_cache,bool lock_started)105 static void bvhcache_unlock(BVHCache *bvh_cache, bool lock_started)
106 {
107 if (lock_started) {
108 BLI_mutex_unlock(&bvh_cache->mutex);
109 }
110 }
111
bvhcache_has_tree(const BVHCache * bvh_cache,const BVHTree * tree)112 bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
113 {
114 if (bvh_cache == NULL) {
115 return false;
116 }
117
118 for (BVHCacheType i = 0; i < BVHTREE_MAX_ITEM; i++) {
119 if (bvh_cache->items[i].tree == tree) {
120 return true;
121 }
122 }
123 return false;
124 }
125
bvhcache_init(void)126 BVHCache *bvhcache_init(void)
127 {
128 BVHCache *cache = MEM_callocN(sizeof(BVHCache), __func__);
129 BLI_mutex_init(&cache->mutex);
130 return cache;
131 }
132 /**
133 * Inserts a BVHTree of the given type under the cache
134 * After that the caller no longer needs to worry when to free the BVHTree
135 * as that will be done when the cache is freed.
136 *
137 * A call to this assumes that there was no previous cached tree of the given type
138 * \warning The #BVHTree can be NULL.
139 */
bvhcache_insert(BVHCache * bvh_cache,BVHTree * tree,BVHCacheType type)140 static void bvhcache_insert(BVHCache *bvh_cache, BVHTree *tree, BVHCacheType type)
141 {
142 BVHCacheItem *item = &bvh_cache->items[type];
143 BLI_assert(!item->is_filled);
144 item->tree = tree;
145 item->is_filled = true;
146 }
147
148 /**
149 * frees a bvhcache
150 */
bvhcache_free(BVHCache * bvh_cache)151 void bvhcache_free(BVHCache *bvh_cache)
152 {
153 for (BVHCacheType index = 0; index < BVHTREE_MAX_ITEM; index++) {
154 BVHCacheItem *item = &bvh_cache->items[index];
155 BLI_bvhtree_free(item->tree);
156 item->tree = NULL;
157 }
158 BLI_mutex_end(&bvh_cache->mutex);
159 MEM_freeN(bvh_cache);
160 }
161
162 /** \} */
163 /* -------------------------------------------------------------------- */
164 /** \name Local Callbacks
165 * \{ */
166
167 /* Math stuff for ray casting on mesh faces and for nearest surface */
168
bvhtree_ray_tri_intersection(const BVHTreeRay * ray,const float UNUSED (m_dist),const float v0[3],const float v1[3],const float v2[3])169 float bvhtree_ray_tri_intersection(const BVHTreeRay *ray,
170 const float UNUSED(m_dist),
171 const float v0[3],
172 const float v1[3],
173 const float v2[3])
174 {
175 float dist;
176
177 #ifdef USE_KDOPBVH_WATERTIGHT
178 if (isect_ray_tri_watertight_v3(ray->origin, ray->isect_precalc, v0, v1, v2, &dist, NULL))
179 #else
180 if (isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON))
181 #endif
182 {
183 return dist;
184 }
185
186 return FLT_MAX;
187 }
188
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])189 float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray,
190 float radius,
191 const float m_dist,
192 const float v0[3],
193 const float v1[3],
194 const float v2[3])
195 {
196
197 float idist;
198 float p1[3];
199 float hit_point[3];
200
201 madd_v3_v3v3fl(p1, ray->origin, ray->direction, m_dist);
202 if (isect_sweeping_sphere_tri_v3(ray->origin, p1, radius, v0, v1, v2, &idist, hit_point)) {
203 return idist * m_dist;
204 }
205
206 return FLT_MAX;
207 }
208
209 /*
210 * BVH from meshes callbacks
211 */
212
213 /* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_faces.
214 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
mesh_faces_nearest_point(void * userdata,int index,const float co[3],BVHTreeNearest * nearest)215 static void mesh_faces_nearest_point(void *userdata,
216 int index,
217 const float co[3],
218 BVHTreeNearest *nearest)
219 {
220 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
221 const MVert *vert = data->vert;
222 const MFace *face = data->face + index;
223
224 const float *t0, *t1, *t2, *t3;
225 t0 = vert[face->v1].co;
226 t1 = vert[face->v2].co;
227 t2 = vert[face->v3].co;
228 t3 = face->v4 ? vert[face->v4].co : NULL;
229
230 do {
231 float nearest_tmp[3], dist_sq;
232
233 closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
234 dist_sq = len_squared_v3v3(co, nearest_tmp);
235
236 if (dist_sq < nearest->dist_sq) {
237 nearest->index = index;
238 nearest->dist_sq = dist_sq;
239 copy_v3_v3(nearest->co, nearest_tmp);
240 normal_tri_v3(nearest->no, t0, t1, t2);
241 }
242
243 t1 = t2;
244 t2 = t3;
245 t3 = NULL;
246
247 } while (t2);
248 }
249 /* copy of function above */
mesh_looptri_nearest_point(void * userdata,int index,const float co[3],BVHTreeNearest * nearest)250 static void mesh_looptri_nearest_point(void *userdata,
251 int index,
252 const float co[3],
253 BVHTreeNearest *nearest)
254 {
255 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
256 const MVert *vert = data->vert;
257 const MLoopTri *lt = &data->looptri[index];
258 const float *vtri_co[3] = {
259 vert[data->loop[lt->tri[0]].v].co,
260 vert[data->loop[lt->tri[1]].v].co,
261 vert[data->loop[lt->tri[2]].v].co,
262 };
263 float nearest_tmp[3], dist_sq;
264
265 closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(vtri_co));
266 dist_sq = len_squared_v3v3(co, nearest_tmp);
267
268 if (dist_sq < nearest->dist_sq) {
269 nearest->index = index;
270 nearest->dist_sq = dist_sq;
271 copy_v3_v3(nearest->co, nearest_tmp);
272 normal_tri_v3(nearest->no, UNPACK3(vtri_co));
273 }
274 }
275 /* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
editmesh_looptri_nearest_point(void * userdata,int index,const float co[3],BVHTreeNearest * nearest)276 static void editmesh_looptri_nearest_point(void *userdata,
277 int index,
278 const float co[3],
279 BVHTreeNearest *nearest)
280 {
281 const BVHTreeFromEditMesh *data = userdata;
282 BMEditMesh *em = data->em;
283 const BMLoop **ltri = (const BMLoop **)em->looptris[index];
284
285 const float *t0, *t1, *t2;
286 t0 = ltri[0]->v->co;
287 t1 = ltri[1]->v->co;
288 t2 = ltri[2]->v->co;
289
290 {
291 float nearest_tmp[3], dist_sq;
292
293 closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
294 dist_sq = len_squared_v3v3(co, nearest_tmp);
295
296 if (dist_sq < nearest->dist_sq) {
297 nearest->index = index;
298 nearest->dist_sq = dist_sq;
299 copy_v3_v3(nearest->co, nearest_tmp);
300 normal_tri_v3(nearest->no, t0, t1, t2);
301 }
302 }
303 }
304
305 /* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_faces.
306 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
mesh_faces_spherecast(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)307 static void mesh_faces_spherecast(void *userdata,
308 int index,
309 const BVHTreeRay *ray,
310 BVHTreeRayHit *hit)
311 {
312 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
313 const MVert *vert = data->vert;
314 const MFace *face = &data->face[index];
315
316 const float *t0, *t1, *t2, *t3;
317 t0 = vert[face->v1].co;
318 t1 = vert[face->v2].co;
319 t2 = vert[face->v3].co;
320 t3 = face->v4 ? vert[face->v4].co : NULL;
321
322 do {
323 float dist;
324 if (ray->radius == 0.0f) {
325 dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
326 }
327 else {
328 dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, t0, t1, t2);
329 }
330
331 if (dist >= 0 && dist < hit->dist) {
332 hit->index = index;
333 hit->dist = dist;
334 madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
335
336 normal_tri_v3(hit->no, t0, t1, t2);
337 }
338
339 t1 = t2;
340 t2 = t3;
341 t3 = NULL;
342
343 } while (t2);
344 }
345 /* copy of function above */
mesh_looptri_spherecast(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)346 static void mesh_looptri_spherecast(void *userdata,
347 int index,
348 const BVHTreeRay *ray,
349 BVHTreeRayHit *hit)
350 {
351 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
352 const MVert *vert = data->vert;
353 const MLoopTri *lt = &data->looptri[index];
354 const float *vtri_co[3] = {
355 vert[data->loop[lt->tri[0]].v].co,
356 vert[data->loop[lt->tri[1]].v].co,
357 vert[data->loop[lt->tri[2]].v].co,
358 };
359 float dist;
360
361 if (ray->radius == 0.0f) {
362 dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
363 }
364 else {
365 dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, UNPACK3(vtri_co));
366 }
367
368 if (dist >= 0 && dist < hit->dist) {
369 hit->index = index;
370 hit->dist = dist;
371 madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
372
373 normal_tri_v3(hit->no, UNPACK3(vtri_co));
374 }
375 }
376 /* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
editmesh_looptri_spherecast(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)377 static void editmesh_looptri_spherecast(void *userdata,
378 int index,
379 const BVHTreeRay *ray,
380 BVHTreeRayHit *hit)
381 {
382 const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
383 BMEditMesh *em = data->em;
384 const BMLoop **ltri = (const BMLoop **)em->looptris[index];
385
386 const float *t0, *t1, *t2;
387 t0 = ltri[0]->v->co;
388 t1 = ltri[1]->v->co;
389 t2 = ltri[2]->v->co;
390
391 {
392 float dist;
393 if (ray->radius == 0.0f) {
394 dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
395 }
396 else {
397 dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, t0, t1, t2);
398 }
399
400 if (dist >= 0 && dist < hit->dist) {
401 hit->index = index;
402 hit->dist = dist;
403 madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
404
405 normal_tri_v3(hit->no, t0, t1, t2);
406 }
407 }
408 }
409
410 /* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_edges.
411 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
mesh_edges_nearest_point(void * userdata,int index,const float co[3],BVHTreeNearest * nearest)412 static void mesh_edges_nearest_point(void *userdata,
413 int index,
414 const float co[3],
415 BVHTreeNearest *nearest)
416 {
417 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
418 const MVert *vert = data->vert;
419 const MEdge *edge = data->edge + index;
420 float nearest_tmp[3], dist_sq;
421
422 const float *t0, *t1;
423 t0 = vert[edge->v1].co;
424 t1 = vert[edge->v2].co;
425
426 closest_to_line_segment_v3(nearest_tmp, co, t0, t1);
427 dist_sq = len_squared_v3v3(nearest_tmp, co);
428
429 if (dist_sq < nearest->dist_sq) {
430 nearest->index = index;
431 nearest->dist_sq = dist_sq;
432 copy_v3_v3(nearest->co, nearest_tmp);
433 sub_v3_v3v3(nearest->no, t0, t1);
434 normalize_v3(nearest->no);
435 }
436 }
437
438 /* Helper, does all the point-spherecast work actually. */
mesh_verts_spherecast_do(int index,const float v[3],const BVHTreeRay * ray,BVHTreeRayHit * hit)439 static void mesh_verts_spherecast_do(int index,
440 const float v[3],
441 const BVHTreeRay *ray,
442 BVHTreeRayHit *hit)
443 {
444 float dist;
445 const float *r1;
446 float r2[3], i1[3];
447 r1 = ray->origin;
448 add_v3_v3v3(r2, r1, ray->direction);
449
450 closest_to_line_segment_v3(i1, v, r1, r2);
451
452 /* No hit if closest point is 'behind' the origin of the ray, or too far away from it. */
453 if ((dot_v3v3v3(r1, i1, r2) >= 0.0f) && ((dist = len_v3v3(r1, i1)) < hit->dist)) {
454 hit->index = index;
455 hit->dist = dist;
456 copy_v3_v3(hit->co, i1);
457 }
458 }
459
editmesh_verts_spherecast(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)460 static void editmesh_verts_spherecast(void *userdata,
461 int index,
462 const BVHTreeRay *ray,
463 BVHTreeRayHit *hit)
464 {
465 const BVHTreeFromEditMesh *data = userdata;
466 BMVert *eve = BM_vert_at_index(data->em->bm, index);
467
468 mesh_verts_spherecast_do(index, eve->co, ray, hit);
469 }
470
471 /* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_verts.
472 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
mesh_verts_spherecast(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)473 static void mesh_verts_spherecast(void *userdata,
474 int index,
475 const BVHTreeRay *ray,
476 BVHTreeRayHit *hit)
477 {
478 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
479 const float *v = data->vert[index].co;
480
481 mesh_verts_spherecast_do(index, v, ray, hit);
482 }
483
484 /* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges.
485 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
mesh_edges_spherecast(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)486 static void mesh_edges_spherecast(void *userdata,
487 int index,
488 const BVHTreeRay *ray,
489 BVHTreeRayHit *hit)
490 {
491 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
492 const MVert *vert = data->vert;
493 const MEdge *edge = &data->edge[index];
494
495 const float radius_sq = square_f(ray->radius);
496 float dist;
497 const float *v1, *v2, *r1;
498 float r2[3], i1[3], i2[3];
499 v1 = vert[edge->v1].co;
500 v2 = vert[edge->v2].co;
501
502 /* In case we get a zero-length edge, handle it as a point! */
503 if (equals_v3v3(v1, v2)) {
504 mesh_verts_spherecast_do(index, v1, ray, hit);
505 return;
506 }
507
508 r1 = ray->origin;
509 add_v3_v3v3(r2, r1, ray->direction);
510
511 if (isect_line_line_v3(v1, v2, r1, r2, i1, i2)) {
512 /* No hit if intersection point is 'behind' the origin of the ray, or too far away from it. */
513 if ((dot_v3v3v3(r1, i2, r2) >= 0.0f) && ((dist = len_v3v3(r1, i2)) < hit->dist)) {
514 const float e_fac = line_point_factor_v3(i1, v1, v2);
515 if (e_fac < 0.0f) {
516 copy_v3_v3(i1, v1);
517 }
518 else if (e_fac > 1.0f) {
519 copy_v3_v3(i1, v2);
520 }
521 /* Ensure ray is really close enough from edge! */
522 if (len_squared_v3v3(i1, i2) <= radius_sq) {
523 hit->index = index;
524 hit->dist = dist;
525 copy_v3_v3(hit->co, i2);
526 }
527 }
528 }
529 }
530
531 /** \} */
532
533 /*
534 * BVH builders
535 */
536
537 /* -------------------------------------------------------------------- */
538 /** \name Vertex Builder
539 * \{ */
540
bvhtree_from_editmesh_verts_create_tree(float epsilon,int tree_type,int axis,BMEditMesh * em,const BLI_bitmap * verts_mask,int verts_num_active)541 static BVHTree *bvhtree_from_editmesh_verts_create_tree(float epsilon,
542 int tree_type,
543 int axis,
544 BMEditMesh *em,
545 const BLI_bitmap *verts_mask,
546 int verts_num_active)
547 {
548 BM_mesh_elem_table_ensure(em->bm, BM_VERT);
549 const int verts_num = em->bm->totvert;
550 if (verts_mask) {
551 BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
552 }
553 else {
554 verts_num_active = verts_num;
555 }
556
557 BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
558
559 if (tree) {
560 for (int i = 0; i < verts_num; i++) {
561 if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
562 continue;
563 }
564 BMVert *eve = BM_vert_at_index(em->bm, i);
565 BLI_bvhtree_insert(tree, i, eve->co, 1);
566 }
567 BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
568 BLI_bvhtree_balance(tree);
569 }
570
571 return tree;
572 }
573
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)574 static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
575 int tree_type,
576 int axis,
577 const MVert *vert,
578 const int verts_num,
579 const BLI_bitmap *verts_mask,
580 int verts_num_active)
581 {
582 BVHTree *tree = NULL;
583
584 if (verts_mask) {
585 BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
586 }
587 else {
588 verts_num_active = verts_num;
589 }
590
591 if (verts_num_active) {
592 tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
593
594 if (tree) {
595 for (int i = 0; i < verts_num; i++) {
596 if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
597 continue;
598 }
599 BLI_bvhtree_insert(tree, i, vert[i].co, 1);
600 }
601 BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
602 BLI_bvhtree_balance(tree);
603 }
604 }
605
606 return tree;
607 }
608
bvhtree_from_mesh_verts_setup_data(BVHTreeFromMesh * data,BVHTree * tree,const bool is_cached,const MVert * vert,const bool vert_allocated)609 static void bvhtree_from_mesh_verts_setup_data(BVHTreeFromMesh *data,
610 BVHTree *tree,
611 const bool is_cached,
612 const MVert *vert,
613 const bool vert_allocated)
614 {
615 memset(data, 0, sizeof(*data));
616
617 data->tree = tree;
618 data->cached = is_cached;
619
620 /* a NULL nearest callback works fine
621 * remember the min distance to point is the same as the min distance to BV of point */
622 data->nearest_callback = NULL;
623 data->raycast_callback = mesh_verts_spherecast;
624
625 data->vert = vert;
626 data->vert_allocated = vert_allocated;
627 }
628
629 /* Builds a bvh tree where nodes are the vertices of the given em */
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 BVHCacheType bvh_cache_type,BVHCache ** bvh_cache_p,ThreadMutex * mesh_eval_mutex)630 BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
631 BMEditMesh *em,
632 const BLI_bitmap *verts_mask,
633 int verts_num_active,
634 float epsilon,
635 int tree_type,
636 int axis,
637 const BVHCacheType bvh_cache_type,
638 BVHCache **bvh_cache_p,
639 ThreadMutex *mesh_eval_mutex)
640 {
641 BVHTree *tree = NULL;
642
643 if (bvh_cache_p) {
644 bool lock_started = false;
645 data->cached = bvhcache_find(
646 bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
647
648 if (data->cached == false) {
649 tree = bvhtree_from_editmesh_verts_create_tree(
650 epsilon, tree_type, axis, em, verts_mask, verts_num_active);
651
652 /* Save on cache for later use */
653 /* printf("BVHTree built and saved on cache\n"); */
654 bvhcache_insert(*bvh_cache_p, tree, bvh_cache_type);
655 data->cached = true;
656 }
657 bvhcache_unlock(*bvh_cache_p, lock_started);
658 }
659 else {
660 tree = bvhtree_from_editmesh_verts_create_tree(
661 epsilon, tree_type, axis, em, verts_mask, verts_num_active);
662 }
663
664 if (tree) {
665 memset(data, 0, sizeof(*data));
666 data->tree = tree;
667 data->em = em;
668 data->nearest_callback = NULL;
669 data->raycast_callback = editmesh_verts_spherecast;
670 data->cached = bvh_cache_p != NULL;
671 }
672
673 return tree;
674 }
675
bvhtree_from_editmesh_verts(BVHTreeFromEditMesh * data,BMEditMesh * em,float epsilon,int tree_type,int axis)676 BVHTree *bvhtree_from_editmesh_verts(
677 BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
678 {
679 return bvhtree_from_editmesh_verts_ex(
680 data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
681 }
682
683 /**
684 * Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!).
685 * \param vert_allocated: if true, vert freeing will be done when freeing data.
686 * \param verts_mask: if not null, true elements give which vert to add to BVH tree.
687 * \param verts_num_active: if >= 0, number of active verts to add to BVH tree
688 * (else will be computed from mask).
689 */
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 BVHCacheType bvh_cache_type,BVHCache ** bvh_cache_p,ThreadMutex * mesh_eval_mutex)690 BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
691 const MVert *vert,
692 const int verts_num,
693 const bool vert_allocated,
694 const BLI_bitmap *verts_mask,
695 int verts_num_active,
696 float epsilon,
697 int tree_type,
698 int axis,
699 const BVHCacheType bvh_cache_type,
700 BVHCache **bvh_cache_p,
701 ThreadMutex *mesh_eval_mutex)
702 {
703 bool in_cache = false;
704 bool lock_started = false;
705 BVHTree *tree = NULL;
706 if (bvh_cache_p) {
707 in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
708 }
709
710 if (in_cache == false) {
711 tree = bvhtree_from_mesh_verts_create_tree(
712 epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
713
714 if (bvh_cache_p) {
715 /* Save on cache for later use */
716 /* printf("BVHTree built and saved on cache\n"); */
717 BVHCache *bvh_cache = *bvh_cache_p;
718 bvhcache_insert(bvh_cache, tree, bvh_cache_type);
719 in_cache = true;
720 }
721 }
722
723 if (bvh_cache_p) {
724 bvhcache_unlock(*bvh_cache_p, lock_started);
725 }
726
727 /* Setup BVHTreeFromMesh */
728 bvhtree_from_mesh_verts_setup_data(data, tree, in_cache, vert, vert_allocated);
729
730 return tree;
731 }
732
733 /** \} */
734
735 /* -------------------------------------------------------------------- */
736 /** \name Edge Builder
737 * \{ */
738
bvhtree_from_editmesh_edges_create_tree(float epsilon,int tree_type,int axis,BMEditMesh * em,const BLI_bitmap * edges_mask,int edges_num_active)739 static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
740 int tree_type,
741 int axis,
742 BMEditMesh *em,
743 const BLI_bitmap *edges_mask,
744 int edges_num_active)
745 {
746 BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
747 const int edges_num = em->bm->totedge;
748
749 if (edges_mask) {
750 BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num));
751 }
752 else {
753 edges_num_active = edges_num;
754 }
755
756 BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
757
758 if (tree) {
759 int i;
760 BMIter iter;
761 BMEdge *eed;
762 BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
763 if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
764 continue;
765 }
766 float co[2][3];
767 copy_v3_v3(co[0], eed->v1->co);
768 copy_v3_v3(co[1], eed->v2->co);
769
770 BLI_bvhtree_insert(tree, i, co[0], 2);
771 }
772 BLI_assert(BLI_bvhtree_get_len(tree) == edges_num_active);
773 BLI_bvhtree_balance(tree);
774 }
775
776 return tree;
777 }
778
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)779 static BVHTree *bvhtree_from_mesh_edges_create_tree(const MVert *vert,
780 const MEdge *edge,
781 const int edge_num,
782 const BLI_bitmap *edges_mask,
783 int edges_num_active,
784 float epsilon,
785 int tree_type,
786 int axis)
787 {
788 BVHTree *tree = NULL;
789
790 if (edges_mask) {
791 BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
792 }
793 else {
794 edges_num_active = edge_num;
795 }
796
797 if (edges_num_active) {
798 /* Create a bvh-tree of the given target */
799 tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
800 if (tree) {
801 for (int i = 0; i < edge_num; i++) {
802 if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
803 continue;
804 }
805 float co[2][3];
806 copy_v3_v3(co[0], vert[edge[i].v1].co);
807 copy_v3_v3(co[1], vert[edge[i].v2].co);
808
809 BLI_bvhtree_insert(tree, i, co[0], 2);
810 }
811 BLI_bvhtree_balance(tree);
812 }
813 }
814
815 return tree;
816 }
817
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)818 static void bvhtree_from_mesh_edges_setup_data(BVHTreeFromMesh *data,
819 BVHTree *tree,
820 const bool is_cached,
821 const MVert *vert,
822 const bool vert_allocated,
823 const MEdge *edge,
824 const bool edge_allocated)
825 {
826 memset(data, 0, sizeof(*data));
827
828 data->tree = tree;
829
830 data->cached = is_cached;
831
832 data->nearest_callback = mesh_edges_nearest_point;
833 data->raycast_callback = mesh_edges_spherecast;
834
835 data->vert = vert;
836 data->vert_allocated = vert_allocated;
837 data->edge = edge;
838 data->edge_allocated = edge_allocated;
839 }
840
841 /* Builds a bvh tree where nodes are the edges of the given em */
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 BVHCacheType bvh_cache_type,BVHCache ** bvh_cache_p,ThreadMutex * mesh_eval_mutex)842 BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
843 BMEditMesh *em,
844 const BLI_bitmap *edges_mask,
845 int edges_num_active,
846 float epsilon,
847 int tree_type,
848 int axis,
849 const BVHCacheType bvh_cache_type,
850 BVHCache **bvh_cache_p,
851 ThreadMutex *mesh_eval_mutex)
852 {
853 BVHTree *tree = NULL;
854
855 if (bvh_cache_p) {
856 bool lock_started = false;
857 data->cached = bvhcache_find(
858 bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
859 BVHCache *bvh_cache = *bvh_cache_p;
860 if (data->cached == false) {
861 tree = bvhtree_from_editmesh_edges_create_tree(
862 epsilon, tree_type, axis, em, edges_mask, edges_num_active);
863
864 /* Save on cache for later use */
865 /* printf("BVHTree built and saved on cache\n"); */
866 bvhcache_insert(bvh_cache, tree, bvh_cache_type);
867 data->cached = true;
868 }
869 bvhcache_unlock(bvh_cache, lock_started);
870 }
871 else {
872 tree = bvhtree_from_editmesh_edges_create_tree(
873 epsilon, tree_type, axis, em, edges_mask, edges_num_active);
874 }
875
876 if (tree) {
877 memset(data, 0, sizeof(*data));
878 data->tree = tree;
879 data->em = em;
880 data->nearest_callback = NULL; /* TODO */
881 data->raycast_callback = NULL; /* TODO */
882 data->cached = bvh_cache_p != NULL;
883 }
884
885 return tree;
886 }
887
bvhtree_from_editmesh_edges(BVHTreeFromEditMesh * data,BMEditMesh * em,float epsilon,int tree_type,int axis)888 BVHTree *bvhtree_from_editmesh_edges(
889 BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
890 {
891 return bvhtree_from_editmesh_edges_ex(
892 data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
893 }
894
895 /**
896 * Builds a bvh tree where nodes are the given edges .
897 * \param vert, vert_allocated: if true, elem freeing will be done when freeing data.
898 * \param edge, edge_allocated: if true, elem freeing will be done when freeing data.
899 * \param edges_mask: if not null, true elements give which vert to add to BVH tree.
900 * \param edges_num_active: if >= 0, number of active edges to add to BVH tree
901 * (else will be computed from mask).
902 */
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 BVHCacheType bvh_cache_type,BVHCache ** bvh_cache_p,ThreadMutex * mesh_eval_mutex)903 BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
904 const MVert *vert,
905 const bool vert_allocated,
906 const MEdge *edge,
907 const int edges_num,
908 const bool edge_allocated,
909 const BLI_bitmap *edges_mask,
910 int edges_num_active,
911 float epsilon,
912 int tree_type,
913 int axis,
914 const BVHCacheType bvh_cache_type,
915 BVHCache **bvh_cache_p,
916 ThreadMutex *mesh_eval_mutex)
917 {
918 bool in_cache = false;
919 bool lock_started = false;
920 BVHTree *tree = NULL;
921 if (bvh_cache_p) {
922 in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
923 }
924
925 if (in_cache == false) {
926 tree = bvhtree_from_mesh_edges_create_tree(
927 vert, edge, edges_num, edges_mask, edges_num_active, epsilon, tree_type, axis);
928
929 if (bvh_cache_p) {
930 BVHCache *bvh_cache = *bvh_cache_p;
931 /* Save on cache for later use */
932 /* printf("BVHTree built and saved on cache\n"); */
933 bvhcache_insert(bvh_cache, tree, bvh_cache_type);
934 in_cache = true;
935 }
936 }
937
938 if (bvh_cache_p) {
939 bvhcache_unlock(*bvh_cache_p, lock_started);
940 }
941
942 /* Setup BVHTreeFromMesh */
943 bvhtree_from_mesh_edges_setup_data(
944 data, tree, in_cache, vert, vert_allocated, edge, edge_allocated);
945
946 return tree;
947 }
948
949 /** \} */
950
951 /* -------------------------------------------------------------------- */
952 /** \name Tessellated Face Builder
953 * \{ */
954
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)955 static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
956 int tree_type,
957 int axis,
958 const MVert *vert,
959 const MFace *face,
960 const int faces_num,
961 const BLI_bitmap *faces_mask,
962 int faces_num_active)
963 {
964 BVHTree *tree = NULL;
965
966 if (faces_num) {
967 if (faces_mask) {
968 BLI_assert(IN_RANGE_INCL(faces_num_active, 0, faces_num));
969 }
970 else {
971 faces_num_active = faces_num;
972 }
973
974 /* Create a bvh-tree of the given target */
975 /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
976 tree = BLI_bvhtree_new(faces_num_active, epsilon, tree_type, axis);
977 if (tree) {
978 if (vert && face) {
979 for (int i = 0; i < faces_num; i++) {
980 float co[4][3];
981 if (faces_mask && !BLI_BITMAP_TEST_BOOL(faces_mask, i)) {
982 continue;
983 }
984
985 copy_v3_v3(co[0], vert[face[i].v1].co);
986 copy_v3_v3(co[1], vert[face[i].v2].co);
987 copy_v3_v3(co[2], vert[face[i].v3].co);
988 if (face[i].v4) {
989 copy_v3_v3(co[3], vert[face[i].v4].co);
990 }
991
992 BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3);
993 }
994 }
995 BLI_assert(BLI_bvhtree_get_len(tree) == faces_num_active);
996 BLI_bvhtree_balance(tree);
997 }
998 }
999
1000 return tree;
1001 }
1002
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)1003 static void bvhtree_from_mesh_faces_setup_data(BVHTreeFromMesh *data,
1004 BVHTree *tree,
1005 const bool is_cached,
1006 const MVert *vert,
1007 const bool vert_allocated,
1008 const MFace *face,
1009 const bool face_allocated)
1010 {
1011 memset(data, 0, sizeof(*data));
1012
1013 data->tree = tree;
1014 data->cached = is_cached;
1015
1016 data->nearest_callback = mesh_faces_nearest_point;
1017 data->raycast_callback = mesh_faces_spherecast;
1018
1019 data->vert = vert;
1020 data->vert_allocated = vert_allocated;
1021 data->face = face;
1022 data->face_allocated = face_allocated;
1023 }
1024
1025 /**
1026 * Builds a bvh tree where nodes are the given tessellated faces
1027 * (note: does not copy given mfaces!).
1028 * \param vert_allocated: if true, vert freeing will be done when freeing data.
1029 * \param face_allocated: if true, face freeing will be done when freeing data.
1030 * \param faces_mask: if not null, true elements give which faces to add to BVH tree.
1031 * \param faces_num_active: if >= 0, number of active faces to add to BVH tree
1032 * (else will be computed from mask).
1033 */
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 BVHCacheType bvh_cache_type,BVHCache ** bvh_cache_p,ThreadMutex * mesh_eval_mutex)1034 BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
1035 const MVert *vert,
1036 const bool vert_allocated,
1037 const MFace *face,
1038 const int numFaces,
1039 const bool face_allocated,
1040 const BLI_bitmap *faces_mask,
1041 int faces_num_active,
1042 float epsilon,
1043 int tree_type,
1044 int axis,
1045 const BVHCacheType bvh_cache_type,
1046 BVHCache **bvh_cache_p,
1047 ThreadMutex *mesh_eval_mutex)
1048 {
1049 bool in_cache = false;
1050 bool lock_started = false;
1051 BVHTree *tree = NULL;
1052 if (bvh_cache_p) {
1053 in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
1054 }
1055
1056 if (in_cache == false) {
1057 tree = bvhtree_from_mesh_faces_create_tree(
1058 epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
1059
1060 if (bvh_cache_p) {
1061 /* Save on cache for later use */
1062 /* printf("BVHTree built and saved on cache\n"); */
1063 BVHCache *bvh_cache = *bvh_cache_p;
1064 bvhcache_insert(bvh_cache, tree, bvh_cache_type);
1065 in_cache = true;
1066 }
1067 }
1068
1069 if (bvh_cache_p) {
1070 bvhcache_unlock(*bvh_cache_p, lock_started);
1071 }
1072
1073 /* Setup BVHTreeFromMesh */
1074 bvhtree_from_mesh_faces_setup_data(
1075 data, tree, in_cache, vert, vert_allocated, face, face_allocated);
1076
1077 return tree;
1078 }
1079
1080 /** \} */
1081
1082 /* -------------------------------------------------------------------- */
1083 /** \name LoopTri Face Builder
1084 * \{ */
1085
bvhtree_from_editmesh_looptri_create_tree(float epsilon,int tree_type,int axis,BMEditMesh * em,const BLI_bitmap * looptri_mask,int looptri_num_active)1086 static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
1087 int tree_type,
1088 int axis,
1089 BMEditMesh *em,
1090 const BLI_bitmap *looptri_mask,
1091 int looptri_num_active)
1092 {
1093 BVHTree *tree = NULL;
1094 const int looptri_num = em->tottri;
1095
1096 if (looptri_num) {
1097 if (looptri_mask) {
1098 BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
1099 }
1100 else {
1101 looptri_num_active = looptri_num;
1102 }
1103
1104 /* Create a bvh-tree of the given target */
1105 /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
1106 tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
1107 if (tree) {
1108 const struct BMLoop *(*looptris)[3] = (void *)em->looptris;
1109
1110 /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden
1111 * and/or selected. Even if the faces themselves are not selected for the snapped
1112 * transform, having a vertex selected means the face (and thus it's tessellated
1113 * triangles) will be moving and will not be a good snap targets. */
1114 for (int i = 0; i < looptri_num; i++) {
1115 const BMLoop **ltri = looptris[i];
1116 bool insert = looptri_mask ? BLI_BITMAP_TEST_BOOL(looptri_mask, i) : true;
1117
1118 if (insert) {
1119 /* No reason found to block hit-testing the triangle for snap, so insert it now.*/
1120 float co[3][3];
1121 copy_v3_v3(co[0], ltri[0]->v->co);
1122 copy_v3_v3(co[1], ltri[1]->v->co);
1123 copy_v3_v3(co[2], ltri[2]->v->co);
1124
1125 BLI_bvhtree_insert(tree, i, co[0], 3);
1126 }
1127 }
1128 BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
1129 BLI_bvhtree_balance(tree);
1130 }
1131 }
1132
1133 return tree;
1134 }
1135
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)1136 static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
1137 int tree_type,
1138 int axis,
1139 const MVert *vert,
1140 const MLoop *mloop,
1141 const MLoopTri *looptri,
1142 const int looptri_num,
1143 const BLI_bitmap *looptri_mask,
1144 int looptri_num_active)
1145 {
1146 BVHTree *tree = NULL;
1147
1148 if (looptri_mask) {
1149 BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
1150 }
1151 else {
1152 looptri_num_active = looptri_num;
1153 }
1154
1155 if (looptri_num_active) {
1156 /* Create a bvh-tree of the given target */
1157 /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
1158 tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
1159 if (tree) {
1160 if (vert && looptri) {
1161 for (int i = 0; i < looptri_num; i++) {
1162 float co[3][3];
1163 if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) {
1164 continue;
1165 }
1166
1167 copy_v3_v3(co[0], vert[mloop[looptri[i].tri[0]].v].co);
1168 copy_v3_v3(co[1], vert[mloop[looptri[i].tri[1]].v].co);
1169 copy_v3_v3(co[2], vert[mloop[looptri[i].tri[2]].v].co);
1170
1171 BLI_bvhtree_insert(tree, i, co[0], 3);
1172 }
1173 }
1174 BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
1175 BLI_bvhtree_balance(tree);
1176 }
1177 }
1178
1179 return tree;
1180 }
1181
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)1182 static void bvhtree_from_mesh_looptri_setup_data(BVHTreeFromMesh *data,
1183 BVHTree *tree,
1184 const bool is_cached,
1185 const MVert *vert,
1186 const bool vert_allocated,
1187 const MLoop *mloop,
1188 const bool loop_allocated,
1189 const MLoopTri *looptri,
1190 const bool looptri_allocated)
1191 {
1192 memset(data, 0, sizeof(*data));
1193
1194 data->tree = tree;
1195 data->cached = is_cached;
1196
1197 data->nearest_callback = mesh_looptri_nearest_point;
1198 data->raycast_callback = mesh_looptri_spherecast;
1199
1200 data->vert = vert;
1201 data->vert_allocated = vert_allocated;
1202 data->loop = mloop;
1203 data->loop_allocated = loop_allocated;
1204 data->looptri = looptri;
1205 data->looptri_allocated = looptri_allocated;
1206 }
1207
1208 /**
1209 * Builds a bvh tree where nodes are the looptri faces of the given bm
1210 */
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 BVHCacheType bvh_cache_type,BVHCache ** bvh_cache_p,ThreadMutex * mesh_eval_mutex)1211 BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
1212 BMEditMesh *em,
1213 const BLI_bitmap *looptri_mask,
1214 int looptri_num_active,
1215 float epsilon,
1216 int tree_type,
1217 int axis,
1218 const BVHCacheType bvh_cache_type,
1219 BVHCache **bvh_cache_p,
1220 ThreadMutex *mesh_eval_mutex)
1221 {
1222 /* BMESH specific check that we have tessfaces,
1223 * we _could_ tessellate here but rather not - campbell */
1224
1225 BVHTree *tree = NULL;
1226 if (bvh_cache_p) {
1227 bool lock_started = false;
1228 bool in_cache = bvhcache_find(
1229 bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
1230 BVHCache *bvh_cache = *bvh_cache_p;
1231
1232 if (in_cache == false) {
1233 tree = bvhtree_from_editmesh_looptri_create_tree(
1234 epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
1235
1236 /* Save on cache for later use */
1237 /* printf("BVHTree built and saved on cache\n"); */
1238 bvhcache_insert(bvh_cache, tree, bvh_cache_type);
1239 }
1240 bvhcache_unlock(bvh_cache, lock_started);
1241 }
1242 else {
1243 tree = bvhtree_from_editmesh_looptri_create_tree(
1244 epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
1245 }
1246
1247 if (tree) {
1248 data->tree = tree;
1249 data->nearest_callback = editmesh_looptri_nearest_point;
1250 data->raycast_callback = editmesh_looptri_spherecast;
1251 data->em = em;
1252 data->cached = bvh_cache_p != NULL;
1253 }
1254 return tree;
1255 }
1256
bvhtree_from_editmesh_looptri(BVHTreeFromEditMesh * data,BMEditMesh * em,float epsilon,int tree_type,int axis)1257 BVHTree *bvhtree_from_editmesh_looptri(
1258 BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
1259 {
1260 return bvhtree_from_editmesh_looptri_ex(
1261 data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
1262 }
1263
1264 /**
1265 * Builds a bvh tree where nodes are the looptri faces of the given dm
1266 *
1267 * \note for editmesh this is currently a duplicate of bvhtree_from_mesh_faces_ex
1268 */
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 BVHCacheType bvh_cache_type,BVHCache ** bvh_cache_p,ThreadMutex * mesh_eval_mutex)1269 BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
1270 const struct MVert *vert,
1271 const bool vert_allocated,
1272 const struct MLoop *mloop,
1273 const bool loop_allocated,
1274 const struct MLoopTri *looptri,
1275 const int looptri_num,
1276 const bool looptri_allocated,
1277 const BLI_bitmap *looptri_mask,
1278 int looptri_num_active,
1279 float epsilon,
1280 int tree_type,
1281 int axis,
1282 const BVHCacheType bvh_cache_type,
1283 BVHCache **bvh_cache_p,
1284 ThreadMutex *mesh_eval_mutex)
1285 {
1286 bool in_cache = false;
1287 bool lock_started = false;
1288 BVHTree *tree = NULL;
1289 if (bvh_cache_p) {
1290 in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
1291 }
1292
1293 if (in_cache == false) {
1294 /* Setup BVHTreeFromMesh */
1295 tree = bvhtree_from_mesh_looptri_create_tree(epsilon,
1296 tree_type,
1297 axis,
1298 vert,
1299 mloop,
1300 looptri,
1301 looptri_num,
1302 looptri_mask,
1303 looptri_num_active);
1304
1305 if (bvh_cache_p) {
1306 BVHCache *bvh_cache = *bvh_cache_p;
1307 bvhcache_insert(bvh_cache, tree, bvh_cache_type);
1308 in_cache = true;
1309 }
1310 }
1311
1312 if (bvh_cache_p) {
1313 bvhcache_unlock(*bvh_cache_p, lock_started);
1314 }
1315
1316 /* Setup BVHTreeFromMesh */
1317 bvhtree_from_mesh_looptri_setup_data(data,
1318 tree,
1319 in_cache,
1320 vert,
1321 vert_allocated,
1322 mloop,
1323 loop_allocated,
1324 looptri,
1325 looptri_allocated);
1326
1327 return tree;
1328 }
1329
loose_verts_map_get(const MEdge * medge,int edges_num,const MVert * UNUSED (mvert),int verts_num,int * r_loose_vert_num)1330 static BLI_bitmap *loose_verts_map_get(const MEdge *medge,
1331 int edges_num,
1332 const MVert *UNUSED(mvert),
1333 int verts_num,
1334 int *r_loose_vert_num)
1335 {
1336 BLI_bitmap *loose_verts_mask = BLI_BITMAP_NEW(verts_num, __func__);
1337 BLI_bitmap_set_all(loose_verts_mask, true, verts_num);
1338
1339 const MEdge *e = medge;
1340 int num_linked_verts = 0;
1341 for (; edges_num--; e++) {
1342 if (BLI_BITMAP_TEST(loose_verts_mask, e->v1)) {
1343 BLI_BITMAP_DISABLE(loose_verts_mask, e->v1);
1344 num_linked_verts++;
1345 }
1346 if (BLI_BITMAP_TEST(loose_verts_mask, e->v2)) {
1347 BLI_BITMAP_DISABLE(loose_verts_mask, e->v2);
1348 num_linked_verts++;
1349 }
1350 }
1351
1352 *r_loose_vert_num = verts_num - num_linked_verts;
1353
1354 return loose_verts_mask;
1355 }
1356
loose_edges_map_get(const MEdge * medge,const int edges_len,int * r_loose_edge_len)1357 static BLI_bitmap *loose_edges_map_get(const MEdge *medge,
1358 const int edges_len,
1359 int *r_loose_edge_len)
1360 {
1361 BLI_bitmap *loose_edges_mask = BLI_BITMAP_NEW(edges_len, __func__);
1362
1363 int loose_edges_len = 0;
1364 const MEdge *e = medge;
1365 for (int i = 0; i < edges_len; i++, e++) {
1366 if (e->flag & ME_LOOSEEDGE) {
1367 BLI_BITMAP_ENABLE(loose_edges_mask, i);
1368 loose_edges_len++;
1369 }
1370 else {
1371 BLI_BITMAP_DISABLE(loose_edges_mask, i);
1372 }
1373 }
1374
1375 *r_loose_edge_len = loose_edges_len;
1376
1377 return loose_edges_mask;
1378 }
1379
looptri_no_hidden_map_get(const MPoly * mpoly,const int looptri_len,int * r_looptri_active_len)1380 static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly,
1381 const int looptri_len,
1382 int *r_looptri_active_len)
1383 {
1384 BLI_bitmap *looptri_mask = BLI_BITMAP_NEW(looptri_len, __func__);
1385
1386 int looptri_no_hidden_len = 0;
1387 int looptri_iter = 0;
1388 const MPoly *mp = mpoly;
1389 while (looptri_iter != looptri_len) {
1390 int mp_totlooptri = mp->totloop - 2;
1391 if (mp->flag & ME_HIDE) {
1392 looptri_iter += mp_totlooptri;
1393 }
1394 else {
1395 while (mp_totlooptri--) {
1396 BLI_BITMAP_ENABLE(looptri_mask, looptri_iter);
1397 looptri_iter++;
1398 looptri_no_hidden_len++;
1399 }
1400 }
1401 mp++;
1402 }
1403
1404 *r_looptri_active_len = looptri_no_hidden_len;
1405
1406 return looptri_mask;
1407 }
1408
1409 /**
1410 * Builds or queries a bvhcache for the cache bvhtree of the request type.
1411 */
BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh * data,struct Mesh * mesh,const BVHCacheType bvh_cache_type,const int tree_type)1412 BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
1413 struct Mesh *mesh,
1414 const BVHCacheType bvh_cache_type,
1415 const int tree_type)
1416 {
1417 BVHTree *tree = NULL;
1418 BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime.bvh_cache;
1419 ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
1420
1421 bool is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
1422
1423 if (is_cached && tree == NULL) {
1424 memset(data, 0, sizeof(*data));
1425 return tree;
1426 }
1427
1428 switch (bvh_cache_type) {
1429 case BVHTREE_FROM_VERTS:
1430 case BVHTREE_FROM_LOOSEVERTS:
1431 if (is_cached == false) {
1432 BLI_bitmap *loose_verts_mask = NULL;
1433 int loose_vert_len = -1;
1434 int verts_len = mesh->totvert;
1435
1436 if (bvh_cache_type == BVHTREE_FROM_LOOSEVERTS) {
1437 loose_verts_mask = loose_verts_map_get(
1438 mesh->medge, mesh->totedge, mesh->mvert, verts_len, &loose_vert_len);
1439 }
1440
1441 tree = bvhtree_from_mesh_verts_ex(data,
1442 mesh->mvert,
1443 verts_len,
1444 false,
1445 loose_verts_mask,
1446 loose_vert_len,
1447 0.0f,
1448 tree_type,
1449 6,
1450 bvh_cache_type,
1451 bvh_cache_p,
1452 mesh_eval_mutex);
1453
1454 if (loose_verts_mask != NULL) {
1455 MEM_freeN(loose_verts_mask);
1456 }
1457 }
1458 else {
1459 /* Setup BVHTreeFromMesh */
1460 bvhtree_from_mesh_verts_setup_data(data, tree, true, mesh->mvert, false);
1461 }
1462 break;
1463
1464 case BVHTREE_FROM_EDGES:
1465 case BVHTREE_FROM_LOOSEEDGES:
1466 if (is_cached == false) {
1467 BLI_bitmap *loose_edges_mask = NULL;
1468 int loose_edges_len = -1;
1469 int edges_len = mesh->totedge;
1470
1471 if (bvh_cache_type == BVHTREE_FROM_LOOSEEDGES) {
1472 loose_edges_mask = loose_edges_map_get(mesh->medge, edges_len, &loose_edges_len);
1473 }
1474
1475 tree = bvhtree_from_mesh_edges_ex(data,
1476 mesh->mvert,
1477 false,
1478 mesh->medge,
1479 edges_len,
1480 false,
1481 loose_edges_mask,
1482 loose_edges_len,
1483 0.0,
1484 tree_type,
1485 6,
1486 bvh_cache_type,
1487 bvh_cache_p,
1488 mesh_eval_mutex);
1489
1490 if (loose_edges_mask != NULL) {
1491 MEM_freeN(loose_edges_mask);
1492 }
1493 }
1494 else {
1495 /* Setup BVHTreeFromMesh */
1496 bvhtree_from_mesh_edges_setup_data(
1497 data, tree, true, mesh->mvert, false, mesh->medge, false);
1498 }
1499 break;
1500
1501 case BVHTREE_FROM_FACES:
1502 if (is_cached == false) {
1503 int num_faces = mesh->totface;
1504 BLI_assert(!(num_faces == 0 && mesh->totpoly != 0));
1505
1506 tree = bvhtree_from_mesh_faces_ex(data,
1507 mesh->mvert,
1508 false,
1509 mesh->mface,
1510 num_faces,
1511 false,
1512 NULL,
1513 -1,
1514 0.0,
1515 tree_type,
1516 6,
1517 bvh_cache_type,
1518 bvh_cache_p,
1519 mesh_eval_mutex);
1520 }
1521 else {
1522 /* Setup BVHTreeFromMesh */
1523 bvhtree_from_mesh_faces_setup_data(
1524 data, tree, true, mesh->mvert, false, mesh->mface, false);
1525 }
1526 break;
1527
1528 case BVHTREE_FROM_LOOPTRI:
1529 case BVHTREE_FROM_LOOPTRI_NO_HIDDEN:
1530 if (is_cached == false) {
1531 const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
1532 int looptri_len = BKE_mesh_runtime_looptri_len(mesh);
1533
1534 int looptri_mask_active_len = -1;
1535 BLI_bitmap *looptri_mask = NULL;
1536 if (bvh_cache_type == BVHTREE_FROM_LOOPTRI_NO_HIDDEN) {
1537 looptri_mask = looptri_no_hidden_map_get(
1538 mesh->mpoly, looptri_len, &looptri_mask_active_len);
1539 }
1540
1541 tree = bvhtree_from_mesh_looptri_ex(data,
1542 mesh->mvert,
1543 false,
1544 mesh->mloop,
1545 false,
1546 mlooptri,
1547 looptri_len,
1548 false,
1549 looptri_mask,
1550 looptri_mask_active_len,
1551 0.0,
1552 tree_type,
1553 6,
1554 bvh_cache_type,
1555 bvh_cache_p,
1556 mesh_eval_mutex);
1557 }
1558 else {
1559 /* Setup BVHTreeFromMesh */
1560 const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
1561 bvhtree_from_mesh_looptri_setup_data(
1562 data, tree, true, mesh->mvert, false, mesh->mloop, false, mlooptri, false);
1563 }
1564 break;
1565 case BVHTREE_FROM_EM_VERTS:
1566 case BVHTREE_FROM_EM_EDGES:
1567 case BVHTREE_FROM_EM_LOOPTRI:
1568 case BVHTREE_MAX_ITEM:
1569 BLI_assert(false);
1570 break;
1571 }
1572
1573 if (data->tree != NULL) {
1574 #ifdef DEBUG
1575 if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) {
1576 printf("tree_type %d obtained instead of %d\n",
1577 BLI_bvhtree_get_tree_type(data->tree),
1578 tree_type);
1579 }
1580 #endif
1581 BLI_assert(data->cached);
1582 }
1583 else {
1584 free_bvhtree_from_mesh(data);
1585 memset(data, 0, sizeof(*data));
1586 }
1587
1588 return tree;
1589 }
1590
1591 /**
1592 * Builds or queries a bvhcache for the cache bvhtree of the request type.
1593 */
BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh * data,struct BMEditMesh * em,const int tree_type,const BVHCacheType bvh_cache_type,BVHCache ** bvh_cache_p,ThreadMutex * mesh_eval_mutex)1594 BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
1595 struct BMEditMesh *em,
1596 const int tree_type,
1597 const BVHCacheType bvh_cache_type,
1598 BVHCache **bvh_cache_p,
1599 ThreadMutex *mesh_eval_mutex)
1600 {
1601 BVHTree *tree = NULL;
1602 bool is_cached = false;
1603
1604 memset(data, 0, sizeof(*data));
1605
1606 if (bvh_cache_p) {
1607 is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
1608
1609 if (is_cached && tree == NULL) {
1610 return tree;
1611 }
1612 }
1613 data->tree = tree;
1614 data->em = em;
1615 data->cached = is_cached;
1616
1617 switch (bvh_cache_type) {
1618 case BVHTREE_FROM_EM_VERTS:
1619 if (is_cached == false) {
1620 tree = bvhtree_from_editmesh_verts_ex(
1621 data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
1622 }
1623 else {
1624 data->nearest_callback = NULL;
1625 data->raycast_callback = editmesh_verts_spherecast;
1626 }
1627 break;
1628
1629 case BVHTREE_FROM_EM_EDGES:
1630 if (is_cached == false) {
1631 tree = bvhtree_from_editmesh_edges_ex(
1632 data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
1633 }
1634 else {
1635 /* Setup BVHTreeFromMesh */
1636 data->nearest_callback = NULL; /* TODO */
1637 data->raycast_callback = NULL; /* TODO */
1638 }
1639 break;
1640
1641 case BVHTREE_FROM_EM_LOOPTRI:
1642 if (is_cached == false) {
1643 tree = bvhtree_from_editmesh_looptri_ex(
1644 data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
1645 }
1646 else {
1647 /* Setup BVHTreeFromMesh */
1648 data->nearest_callback = editmesh_looptri_nearest_point;
1649 data->raycast_callback = editmesh_looptri_spherecast;
1650 }
1651 break;
1652 case BVHTREE_FROM_VERTS:
1653 case BVHTREE_FROM_EDGES:
1654 case BVHTREE_FROM_FACES:
1655 case BVHTREE_FROM_LOOPTRI:
1656 case BVHTREE_FROM_LOOPTRI_NO_HIDDEN:
1657 case BVHTREE_FROM_LOOSEVERTS:
1658 case BVHTREE_FROM_LOOSEEDGES:
1659 case BVHTREE_MAX_ITEM:
1660 BLI_assert(false);
1661 break;
1662 }
1663
1664 if (data->tree != NULL) {
1665 #ifdef DEBUG
1666 if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) {
1667 printf("tree_type %d obtained instead of %d\n",
1668 BLI_bvhtree_get_tree_type(data->tree),
1669 tree_type);
1670 }
1671 #endif
1672 BLI_assert(data->cached);
1673 }
1674 else {
1675 free_bvhtree_from_editmesh(data);
1676 memset(data, 0, sizeof(*data));
1677 }
1678
1679 return tree;
1680 }
1681
1682 /** \} */
1683
1684 /* Frees data allocated by a call to bvhtree_from_editmesh_*. */
free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh * data)1685 void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
1686 {
1687 if (data->tree) {
1688 if (!data->cached) {
1689 BLI_bvhtree_free(data->tree);
1690 }
1691 memset(data, 0, sizeof(*data));
1692 }
1693 }
1694
1695 /* Frees data allocated by a call to bvhtree_from_mesh_*. */
free_bvhtree_from_mesh(struct BVHTreeFromMesh * data)1696 void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
1697 {
1698 if (data->tree && !data->cached) {
1699 BLI_bvhtree_free(data->tree);
1700 }
1701
1702 if (data->vert_allocated) {
1703 MEM_freeN((void *)data->vert);
1704 }
1705 if (data->edge_allocated) {
1706 MEM_freeN((void *)data->edge);
1707 }
1708 if (data->face_allocated) {
1709 MEM_freeN((void *)data->face);
1710 }
1711 if (data->loop_allocated) {
1712 MEM_freeN((void *)data->loop);
1713 }
1714 if (data->looptri_allocated) {
1715 MEM_freeN((void *)data->looptri);
1716 }
1717
1718 memset(data, 0, sizeof(*data));
1719 }
1720