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
17 /** \file
18 * \ingroup edtransform
19 */
20
21 #include <stdlib.h>
22
23 #include "MEM_guardedalloc.h"
24
25 #include "BLI_ghash.h"
26 #include "BLI_kdopbvh.h"
27 #include "BLI_listbase.h"
28 #include "BLI_math.h"
29 #include "BLI_memarena.h"
30 #include "BLI_utildefines.h"
31
32 #include "DNA_armature_types.h"
33 #include "DNA_curve_types.h"
34 #include "DNA_mesh_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_view3d_types.h"
40
41 #include "BKE_armature.h"
42 #include "BKE_bvhutils.h"
43 #include "BKE_curve.h"
44 #include "BKE_duplilist.h"
45 #include "BKE_editmesh.h"
46 #include "BKE_layer.h"
47 #include "BKE_mesh.h"
48 #include "BKE_mesh_runtime.h"
49 #include "BKE_object.h"
50 #include "BKE_tracking.h"
51
52 #include "DEG_depsgraph_query.h"
53
54 #include "ED_armature.h"
55 #include "ED_transform_snap_object_context.h"
56 #include "ED_view3d.h"
57
58 /* -------------------------------------------------------------------- */
59 /** \name Internal Data Types
60 * \{ */
61
62 #define MAX_CLIPPLANE_LEN 3
63
64 enum eViewProj {
65 VIEW_PROJ_NONE = -1,
66 VIEW_PROJ_ORTHO = 0,
67 VIEW_PROJ_PERSP = -1,
68 };
69
70 typedef struct SnapData {
71 float mval[2];
72 float pmat[4][4]; /* perspective matrix */
73 float win_size[2]; /* win x and y */
74 enum eViewProj view_proj;
75 float clip_plane[MAX_CLIPPLANE_LEN][4];
76 short clip_plane_len;
77 short snap_to_flag;
78 bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
79 } SnapData;
80
81 typedef struct SnapObjectData {
82 enum {
83 SNAP_MESH = 1,
84 SNAP_EDIT_MESH,
85 } type;
86
87 BVHTree *bvhtree[2]; /* MESH: loose edges, loose verts
88 * EDIT_MESH: verts, edges. */
89 bool cached[2];
90
91 union {
92 struct {
93 /* SNAP_MESH */
94 BVHTreeFromMesh treedata_mesh;
95 const struct MPoly *poly;
96 uint has_looptris : 1;
97 uint has_loose_edge : 1;
98 uint has_loose_vert : 1;
99 };
100 struct {
101 /* SNAP_EDIT_MESH */
102 BVHTreeFromEditMesh treedata_editmesh;
103 float min[3], max[3];
104 struct Mesh_Runtime *mesh_runtime;
105 };
106 };
107 } SnapObjectData;
108
109 struct SnapObjectContext {
110 Scene *scene;
111
112 int flag;
113
114 /* Optional: when performing screen-space projection.
115 * otherwise this doesn't take viewport into account. */
116 bool use_v3d;
117 struct {
118 const struct View3D *v3d;
119 const struct ARegion *region;
120 } v3d_data;
121
122 /* Object -> SnapObjectData map */
123 struct {
124 GHash *object_map;
125 /** Map object-data to objects so objects share edit mode data. */
126 GHash *data_to_object_map;
127 MemArena *mem_arena;
128 } cache;
129
130 /* Filter data, returns true to check this value */
131 struct {
132 struct {
133 bool (*test_vert_fn)(BMVert *, void *user_data);
134 bool (*test_edge_fn)(BMEdge *, void *user_data);
135 bool (*test_face_fn)(BMFace *, void *user_data);
136 void *user_data;
137 } edit_mesh;
138 } callbacks;
139 };
140
141 /** \} */
142
143 /* -------------------------------------------------------------------- */
144 /** \name Utilities
145 * \{ */
146
editmesh_eval_final_is_bmesh(const BMEditMesh * em)147 static bool editmesh_eval_final_is_bmesh(const BMEditMesh *em)
148 {
149 return (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH);
150 }
151
152 /** \} */
153
154 /* -------------------------------------------------------------------- */
155 /** \name Snap Object Data
156 * \{ */
157
158 /**
159 * Calculate the minimum and maximum coordinates of the box that encompasses this mesh.
160 */
bm_mesh_minmax(BMesh * bm,float r_min[3],float r_max[3])161 static void bm_mesh_minmax(BMesh *bm, float r_min[3], float r_max[3])
162 {
163 INIT_MINMAX(r_min, r_max);
164 BMIter iter;
165 BMVert *v;
166
167 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
168 minmax_v3v3_v3(r_min, r_max, v->co);
169 }
170 }
171
snap_object_data_mesh_clear(SnapObjectData * sod)172 static void snap_object_data_mesh_clear(SnapObjectData *sod)
173 {
174 BLI_assert(sod->type == SNAP_MESH);
175 for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) {
176 if (!sod->cached[i]) {
177 BLI_bvhtree_free(sod->bvhtree[i]);
178 }
179 sod->bvhtree[i] = NULL;
180 }
181 free_bvhtree_from_mesh(&sod->treedata_mesh);
182 }
183
snap_object_data_editmesh_clear(SnapObjectData * sod)184 static void snap_object_data_editmesh_clear(SnapObjectData *sod)
185 {
186 BLI_assert(sod->type == SNAP_EDIT_MESH);
187 for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) {
188 if (!sod->cached[i]) {
189 BLI_bvhtree_free(sod->bvhtree[i]);
190 }
191 sod->bvhtree[i] = NULL;
192 }
193 free_bvhtree_from_editmesh(&sod->treedata_editmesh);
194 }
195
snap_object_data_clear(SnapObjectData * sod)196 static void snap_object_data_clear(SnapObjectData *sod)
197 {
198 switch (sod->type) {
199 case SNAP_MESH: {
200 snap_object_data_mesh_clear(sod);
201 break;
202 }
203 case SNAP_EDIT_MESH: {
204 snap_object_data_editmesh_clear(sod);
205 break;
206 }
207 }
208 memset(&sod->type, 0x0, sizeof(*sod) - offsetof(SnapObjectData, type));
209 }
210
snap_object_data_lookup(SnapObjectContext * sctx,Object * ob)211 static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob)
212 {
213 SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
214 if (sod == NULL) {
215 if (sctx->cache.data_to_object_map != NULL) {
216 ob = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob->data);
217 /* Could be NULl when mixing edit-mode and non edit-mode objects. */
218 if (ob != NULL) {
219 sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
220 }
221 }
222 }
223 return sod;
224 }
225
snap_object_data_mesh_get(SnapObjectContext * sctx,Object * ob)226 static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob)
227 {
228 SnapObjectData *sod;
229 void **sod_p;
230 bool init = false;
231
232 if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
233 sod = *sod_p;
234 if (sod->type != SNAP_MESH) {
235 snap_object_data_clear(sod);
236 init = true;
237 }
238 }
239 else {
240 sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
241 init = true;
242 }
243
244 if (init) {
245 sod->type = SNAP_MESH;
246 /* start assuming that it has each of these element types */
247 sod->has_looptris = true;
248 sod->has_loose_edge = true;
249 sod->has_loose_vert = true;
250 }
251
252 return sod;
253 }
254
snap_object_data_editmesh_runtime_get(Object * ob)255 static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob)
256 {
257 BMEditMesh *em = BKE_editmesh_from_object(ob);
258 if (em->mesh_eval_final) {
259 return &em->mesh_eval_final->runtime;
260 }
261 if (em->mesh_eval_cage) {
262 return &em->mesh_eval_cage->runtime;
263 }
264
265 return &((Mesh *)ob->data)->runtime;
266 }
267
snap_object_data_editmesh_get(SnapObjectContext * sctx,Object * ob,BMEditMesh * em)268 static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
269 Object *ob,
270 BMEditMesh *em)
271 {
272 SnapObjectData *sod;
273 void **sod_p;
274 bool init = false, init_min_max = true, clear_cache = false;
275
276 {
277 /* Use object-data as the key in ghash since the editmesh
278 * is used to create bvhtree and is the same for each linked object. */
279 if (sctx->cache.data_to_object_map == NULL) {
280 sctx->cache.data_to_object_map = BLI_ghash_ptr_new(__func__);
281 }
282 void **ob_p;
283 if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob->data, &ob_p)) {
284 ob = *ob_p;
285 }
286 else {
287 *ob_p = ob;
288 }
289 }
290
291 if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
292 sod = *sod_p;
293 bool clear = false;
294 /* Check if the geometry has changed. */
295 if (sod->type != SNAP_EDIT_MESH) {
296 clear = true;
297 }
298 else if (sod->treedata_editmesh.em != em) {
299 clear_cache = true;
300 init = true;
301 }
302 else if (sod->mesh_runtime) {
303 if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob)) {
304 clear_cache = true;
305 init = true;
306 }
307 else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached &&
308 !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) {
309 /* The tree is owned by the EditMesh and may have been freed since we last used! */
310 clear = true;
311 }
312 else if (sod->bvhtree[0] && sod->cached[0] &&
313 !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) {
314 /* The tree is owned by the EditMesh and may have been freed since we last used! */
315 clear = true;
316 }
317 else if (sod->bvhtree[1] && sod->cached[1] &&
318 !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) {
319 /* The tree is owned by the EditMesh and may have been freed since we last used! */
320 clear = true;
321 }
322 }
323
324 if (clear) {
325 snap_object_data_clear(sod);
326 init = true;
327 }
328 }
329 else {
330 sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
331 init = true;
332 }
333
334 if (init) {
335 sod->type = SNAP_EDIT_MESH;
336 sod->treedata_editmesh.em = em;
337
338 if (clear_cache) {
339 /* Only init min and max when you have a non-custom bvhtree pending. */
340 init_min_max = false;
341 if (sod->treedata_editmesh.cached) {
342 sod->treedata_editmesh.tree = NULL;
343 init_min_max = true;
344 }
345 for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) {
346 if (sod->cached[i]) {
347 sod->bvhtree[i] = NULL;
348 init_min_max = true;
349 }
350 }
351 }
352
353 if (init_min_max) {
354 bm_mesh_minmax(em->bm, sod->min, sod->max);
355 }
356
357 sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob);
358 }
359
360 return sod;
361 }
362
363 /** \} */
364
365 /* -------------------------------------------------------------------- */
366 /** \name Iterator
367 * \{ */
368
369 typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
370 Object *ob,
371 float obmat[4][4],
372 bool use_obedit,
373 bool use_backface_culling,
374 bool is_object_active,
375 void *data);
376
377 /**
378 * Walks through all objects in the scene to create the list of objects to snap.
379 */
iter_snap_objects(SnapObjectContext * sctx,Depsgraph * depsgraph,const struct SnapObjectParams * params,IterSnapObjsCallback sob_callback,void * data)380 static void iter_snap_objects(SnapObjectContext *sctx,
381 Depsgraph *depsgraph,
382 const struct SnapObjectParams *params,
383 IterSnapObjsCallback sob_callback,
384 void *data)
385 {
386 ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
387 const View3D *v3d = sctx->v3d_data.v3d;
388 const eSnapSelect snap_select = params->snap_select;
389 const bool use_object_edit_cage = params->use_object_edit_cage;
390 const bool use_backface_culling = params->use_backface_culling;
391
392 Base *base_act = view_layer->basact;
393 for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
394 if (!BASE_VISIBLE(v3d, base)) {
395 continue;
396 }
397
398 if (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE) {
399 /* pass */
400 }
401 else if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) {
402 continue;
403 }
404
405 const bool is_object_active = (base == base_act);
406 if (snap_select == SNAP_NOT_SELECTED) {
407 if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) {
408 continue;
409 }
410 }
411 else if (snap_select == SNAP_NOT_ACTIVE) {
412 if (is_object_active) {
413 continue;
414 }
415 }
416
417 Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object);
418 if (obj_eval->transflag & OB_DUPLI) {
419 DupliObject *dupli_ob;
420 ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval);
421 for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
422 sob_callback(sctx,
423 dupli_ob->ob,
424 dupli_ob->mat,
425 use_object_edit_cage,
426 use_backface_culling,
427 is_object_active,
428 data);
429 }
430 free_object_duplilist(lb);
431 }
432
433 sob_callback(sctx,
434 obj_eval,
435 obj_eval->obmat,
436 use_object_edit_cage,
437 use_backface_culling,
438 is_object_active,
439 data);
440 }
441 }
442
443 /** \} */
444
445 /* -------------------------------------------------------------------- */
446 /** \name Ray Cast Funcs
447 * \{ */
448
449 /* Store all ray-hits
450 * Support for storing all depths, not just the first (raycast 'all') */
451
452 struct RayCastAll_Data {
453 void *bvhdata;
454
455 /* internal vars for adding depths */
456 BVHTree_RayCastCallback raycast_callback;
457
458 const float (*obmat)[4];
459 const float (*timat)[3];
460
461 float len_diff;
462 float local_scale;
463
464 Object *ob;
465 uint ob_uuid;
466
467 /* output data */
468 ListBase *hit_list;
469 bool retval;
470 };
471
hit_depth_create(const float depth,const float co[3],const float no[3],int index,Object * ob,const float obmat[4][4],uint ob_uuid)472 static struct SnapObjectHitDepth *hit_depth_create(const float depth,
473 const float co[3],
474 const float no[3],
475 int index,
476 Object *ob,
477 const float obmat[4][4],
478 uint ob_uuid)
479 {
480 struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__);
481
482 hit->depth = depth;
483 copy_v3_v3(hit->co, co);
484 copy_v3_v3(hit->no, no);
485 hit->index = index;
486
487 hit->ob = ob;
488 copy_m4_m4(hit->obmat, (float(*)[4])obmat);
489 hit->ob_uuid = ob_uuid;
490
491 return hit;
492 }
493
hit_depth_cmp(const void * arg1,const void * arg2)494 static int hit_depth_cmp(const void *arg1, const void *arg2)
495 {
496 const struct SnapObjectHitDepth *h1 = arg1;
497 const struct SnapObjectHitDepth *h2 = arg2;
498 int val = 0;
499
500 if (h1->depth < h2->depth) {
501 val = -1;
502 }
503 else if (h1->depth > h2->depth) {
504 val = 1;
505 }
506
507 return val;
508 }
509
raycast_all_cb(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)510 static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
511 {
512 struct RayCastAll_Data *data = userdata;
513 data->raycast_callback(data->bvhdata, index, ray, hit);
514 if (hit->index != -1) {
515 /* get all values in worldspace */
516 float location[3], normal[3];
517 float depth;
518
519 /* worldspace location */
520 mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co);
521 depth = (hit->dist + data->len_diff) / data->local_scale;
522
523 /* worldspace normal */
524 copy_v3_v3(normal, hit->no);
525 mul_m3_v3((float(*)[3])data->timat, normal);
526 normalize_v3(normal);
527
528 struct SnapObjectHitDepth *hit_item = hit_depth_create(
529 depth, location, normal, hit->index, data->ob, data->obmat, data->ob_uuid);
530 BLI_addtail(data->hit_list, hit_item);
531 }
532 }
533
raycast_tri_backface_culling_test(const float dir[3],const float v0[3],const float v1[3],const float v2[3],float no[3])534 static bool raycast_tri_backface_culling_test(
535 const float dir[3], const float v0[3], const float v1[3], const float v2[3], float no[3])
536 {
537 cross_tri_v3(no, v0, v1, v2);
538 return dot_v3v3(no, dir) < 0.0f;
539 }
540
541 /* Callback to raycast with backface culling (Mesh). */
mesh_looptri_raycast_backface_culling_cb(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)542 static void mesh_looptri_raycast_backface_culling_cb(void *userdata,
543 int index,
544 const BVHTreeRay *ray,
545 BVHTreeRayHit *hit)
546 {
547 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
548 const MVert *vert = data->vert;
549 const MLoopTri *lt = &data->looptri[index];
550 const float *vtri_co[3] = {
551 vert[data->loop[lt->tri[0]].v].co,
552 vert[data->loop[lt->tri[1]].v].co,
553 vert[data->loop[lt->tri[2]].v].co,
554 };
555 float dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
556
557 if (dist >= 0 && dist < hit->dist) {
558 float no[3];
559 if (raycast_tri_backface_culling_test(ray->direction, UNPACK3(vtri_co), no)) {
560 hit->index = index;
561 hit->dist = dist;
562 madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
563 normalize_v3_v3(hit->no, no);
564 }
565 }
566 }
567
568 /* Callback to raycast with backface culling (EditMesh). */
editmesh_looptri_raycast_backface_culling_cb(void * userdata,int index,const BVHTreeRay * ray,BVHTreeRayHit * hit)569 static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
570 int index,
571 const BVHTreeRay *ray,
572 BVHTreeRayHit *hit)
573 {
574 const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
575 BMEditMesh *em = data->em;
576 const BMLoop **ltri = (const BMLoop **)em->looptris[index];
577
578 const float *t0, *t1, *t2;
579 t0 = ltri[0]->v->co;
580 t1 = ltri[1]->v->co;
581 t2 = ltri[2]->v->co;
582
583 {
584 float dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
585
586 if (dist >= 0 && dist < hit->dist) {
587 float no[3];
588 if (raycast_tri_backface_culling_test(ray->direction, t0, t1, t2, no)) {
589 hit->index = index;
590 hit->dist = dist;
591 madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
592 normalize_v3_v3(hit->no, no);
593 }
594 }
595 }
596 }
597
raycastMesh(SnapObjectContext * sctx,const float ray_start[3],const float ray_dir[3],Object * ob,Mesh * me,const float obmat[4][4],const uint ob_index,bool use_hide,bool use_backface_culling,float * ray_depth,float r_loc[3],float r_no[3],int * r_index,ListBase * r_hit_list)598 static bool raycastMesh(SnapObjectContext *sctx,
599 const float ray_start[3],
600 const float ray_dir[3],
601 Object *ob,
602 Mesh *me,
603 const float obmat[4][4],
604 const uint ob_index,
605 bool use_hide,
606 bool use_backface_culling,
607 /* read/write args */
608 float *ray_depth,
609 /* return args */
610 float r_loc[3],
611 float r_no[3],
612 int *r_index,
613 ListBase *r_hit_list)
614 {
615 bool retval = false;
616
617 if (me->totpoly == 0) {
618 return retval;
619 }
620
621 float imat[4][4];
622 float ray_start_local[3], ray_normal_local[3];
623 float local_scale, local_depth, len_diff = 0.0f;
624
625 invert_m4_m4(imat, obmat);
626
627 copy_v3_v3(ray_start_local, ray_start);
628 copy_v3_v3(ray_normal_local, ray_dir);
629
630 mul_m4_v3(imat, ray_start_local);
631 mul_mat3_m4_v3(imat, ray_normal_local);
632
633 /* local scale in normal direction */
634 local_scale = normalize_v3(ray_normal_local);
635 local_depth = *ray_depth;
636 if (local_depth != BVH_RAYCAST_DIST_MAX) {
637 local_depth *= local_scale;
638 }
639
640 /* Test BoundBox */
641 BoundBox *bb = BKE_mesh_boundbox_get(ob);
642 if (bb) {
643 /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
644 if (!isect_ray_aabb_v3_simple(
645 ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, NULL)) {
646 return retval;
647 }
648 }
649 /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
650 * very far away ray_start values (as returned in case of ortho view3d), see T50486, T38358.
651 */
652 if (len_diff > 400.0f) {
653 len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
654 madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
655 local_depth -= len_diff;
656 }
657 else {
658 len_diff = 0.0f;
659 }
660
661 SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob);
662
663 BVHTreeFromMesh *treedata = &sod->treedata_mesh;
664
665 /* The tree is owned by the Mesh and may have been freed since we last used. */
666 if (treedata->tree) {
667 BLI_assert(treedata->cached);
668 if (!bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) {
669 free_bvhtree_from_mesh(treedata);
670 }
671 else {
672 /* Update Pointers. */
673 if (treedata->vert && treedata->vert_allocated == false) {
674 treedata->vert = me->mvert;
675 }
676 if (treedata->loop && treedata->loop_allocated == false) {
677 treedata->loop = me->mloop;
678 }
679 if (treedata->looptri && treedata->looptri_allocated == false) {
680 treedata->looptri = BKE_mesh_runtime_looptri_ensure(me);
681 }
682 /* required for snapping with occlusion. */
683 treedata->edge = me->medge;
684 sod->poly = me->mpoly;
685 }
686 }
687
688 if (treedata->tree == NULL) {
689 if (use_hide) {
690 BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI_NO_HIDDEN, 4);
691 }
692 else {
693 BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4);
694 }
695
696 /* required for snapping with occlusion. */
697 treedata->edge = me->medge;
698 sod->poly = me->mpoly;
699
700 if (treedata->tree == NULL) {
701 return retval;
702 }
703 }
704
705 float timat[3][3]; /* transpose inverse matrix for normals */
706 transpose_m3_m4(timat, imat);
707
708 if (r_hit_list) {
709 struct RayCastAll_Data data;
710
711 data.bvhdata = treedata;
712 data.raycast_callback = treedata->raycast_callback;
713 data.obmat = obmat;
714 data.timat = timat;
715 data.len_diff = len_diff;
716 data.local_scale = local_scale;
717 data.ob = ob;
718 data.ob_uuid = ob_index;
719 data.hit_list = r_hit_list;
720 data.retval = retval;
721
722 BLI_bvhtree_ray_cast_all(treedata->tree,
723 ray_start_local,
724 ray_normal_local,
725 0.0f,
726 *ray_depth,
727 raycast_all_cb,
728 &data);
729
730 retval = data.retval;
731 }
732 else {
733 BVHTreeRayHit hit = {
734 .index = -1,
735 .dist = local_depth,
736 };
737
738 if (BLI_bvhtree_ray_cast(treedata->tree,
739 ray_start_local,
740 ray_normal_local,
741 0.0f,
742 &hit,
743 use_backface_culling ? mesh_looptri_raycast_backface_culling_cb :
744 treedata->raycast_callback,
745 treedata) != -1) {
746 hit.dist += len_diff;
747 hit.dist /= local_scale;
748 if (hit.dist <= *ray_depth) {
749 *ray_depth = hit.dist;
750 copy_v3_v3(r_loc, hit.co);
751
752 /* back to worldspace */
753 mul_m4_v3(obmat, r_loc);
754
755 if (r_no) {
756 copy_v3_v3(r_no, hit.no);
757 mul_m3_v3(timat, r_no);
758 normalize_v3(r_no);
759 }
760
761 retval = true;
762
763 if (r_index) {
764 *r_index = treedata->looptri[hit.index].poly;
765 }
766 }
767 }
768 }
769
770 return retval;
771 }
772
raycastEditMesh(SnapObjectContext * sctx,const float ray_start[3],const float ray_dir[3],Object * ob,BMEditMesh * em,const float obmat[4][4],const uint ob_index,bool use_backface_culling,float * ray_depth,float r_loc[3],float r_no[3],int * r_index,ListBase * r_hit_list)773 static bool raycastEditMesh(SnapObjectContext *sctx,
774 const float ray_start[3],
775 const float ray_dir[3],
776 Object *ob,
777 BMEditMesh *em,
778 const float obmat[4][4],
779 const uint ob_index,
780 bool use_backface_culling,
781 /* read/write args */
782 float *ray_depth,
783 /* return args */
784 float r_loc[3],
785 float r_no[3],
786 int *r_index,
787 ListBase *r_hit_list)
788 {
789 bool retval = false;
790 if (em->bm->totface == 0) {
791 return retval;
792 }
793
794 float imat[4][4];
795 float ray_start_local[3], ray_normal_local[3];
796 float local_scale, local_depth, len_diff = 0.0f;
797
798 invert_m4_m4(imat, obmat);
799
800 copy_v3_v3(ray_start_local, ray_start);
801 copy_v3_v3(ray_normal_local, ray_dir);
802
803 mul_m4_v3(imat, ray_start_local);
804 mul_mat3_m4_v3(imat, ray_normal_local);
805
806 /* local scale in normal direction */
807 local_scale = normalize_v3(ray_normal_local);
808 local_depth = *ray_depth;
809 if (local_depth != BVH_RAYCAST_DIST_MAX) {
810 local_depth *= local_scale;
811 }
812
813 SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em);
814
815 /* Test BoundBox */
816
817 /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
818 if (!isect_ray_aabb_v3_simple(
819 ray_start_local, ray_normal_local, sod->min, sod->max, &len_diff, NULL)) {
820 return retval;
821 }
822
823 /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
824 * very far away ray_start values (as returned in case of ortho view3d), see T50486, T38358.
825 */
826 if (len_diff > 400.0f) {
827 len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
828 madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
829 local_depth -= len_diff;
830 }
831 else {
832 len_diff = 0.0f;
833 }
834
835 BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh;
836
837 if (treedata->tree == NULL) {
838 /* Operators only update the editmesh looptris of the original mesh. */
839 BLI_assert(sod->treedata_editmesh.em == BKE_editmesh_from_object(DEG_get_original_object(ob)));
840 em = sod->treedata_editmesh.em;
841
842 if (sctx->callbacks.edit_mesh.test_face_fn) {
843 BMesh *bm = em->bm;
844 BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri);
845
846 BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
847 int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
848 bm,
849 elem_mask,
850 sctx->callbacks.edit_mesh.test_face_fn,
851 sctx->callbacks.edit_mesh.user_data);
852
853 bvhtree_from_editmesh_looptri_ex(
854 treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL, NULL);
855
856 MEM_freeN(elem_mask);
857 }
858 else {
859 /* Only cache if bvhtree is created without a mask.
860 * This helps keep a standardized bvhtree in cache. */
861 BKE_bvhtree_from_editmesh_get(treedata,
862 em,
863 4,
864 BVHTREE_FROM_EM_LOOPTRI,
865 &sod->mesh_runtime->bvh_cache,
866 sod->mesh_runtime->eval_mutex);
867 }
868
869 if (treedata->tree == NULL) {
870 return retval;
871 }
872 }
873
874 float timat[3][3]; /* transpose inverse matrix for normals */
875 transpose_m3_m4(timat, imat);
876
877 if (r_hit_list) {
878 struct RayCastAll_Data data;
879
880 data.bvhdata = treedata;
881 data.raycast_callback = treedata->raycast_callback;
882 data.obmat = obmat;
883 data.timat = timat;
884 data.len_diff = len_diff;
885 data.local_scale = local_scale;
886 data.ob = ob;
887 data.ob_uuid = ob_index;
888 data.hit_list = r_hit_list;
889 data.retval = retval;
890
891 BLI_bvhtree_ray_cast_all(treedata->tree,
892 ray_start_local,
893 ray_normal_local,
894 0.0f,
895 *ray_depth,
896 raycast_all_cb,
897 &data);
898
899 retval = data.retval;
900 }
901 else {
902 BVHTreeRayHit hit = {
903 .index = -1,
904 .dist = local_depth,
905 };
906
907 if (BLI_bvhtree_ray_cast(treedata->tree,
908 ray_start_local,
909 ray_normal_local,
910 0.0f,
911 &hit,
912 use_backface_culling ? editmesh_looptri_raycast_backface_culling_cb :
913 treedata->raycast_callback,
914 treedata) != -1) {
915 hit.dist += len_diff;
916 hit.dist /= local_scale;
917 if (hit.dist <= *ray_depth) {
918 *ray_depth = hit.dist;
919 copy_v3_v3(r_loc, hit.co);
920
921 /* back to worldspace */
922 mul_m4_v3(obmat, r_loc);
923
924 if (r_no) {
925 copy_v3_v3(r_no, hit.no);
926 mul_m3_v3(timat, r_no);
927 normalize_v3(r_no);
928 }
929
930 retval = true;
931
932 if (r_index) {
933 em = sod->treedata_editmesh.em;
934
935 *r_index = BM_elem_index_get(em->looptris[hit.index][0]->f);
936 }
937 }
938 }
939 }
940
941 return retval;
942 }
943
944 struct RaycastObjUserData {
945 const float *ray_start;
946 const float *ray_dir;
947 uint ob_index;
948 /* read/write args */
949 float *ray_depth;
950 /* return args */
951 float *r_loc;
952 float *r_no;
953 int *r_index;
954 Object **r_ob;
955 float (*r_obmat)[4];
956 ListBase *r_hit_list;
957 bool use_occlusion_test;
958 bool ret;
959 };
960
961 /**
962 * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
963 *
964 * \note Duplicate args here are documented at #snapObjectsRay
965 */
raycast_obj_fn(SnapObjectContext * sctx,Object * ob,float obmat[4][4],bool use_obedit,bool use_backface_culling,bool is_object_active,void * data)966 static void raycast_obj_fn(SnapObjectContext *sctx,
967 Object *ob,
968 float obmat[4][4],
969 bool use_obedit,
970 bool use_backface_culling,
971 bool is_object_active,
972 void *data)
973 {
974 struct RaycastObjUserData *dt = data;
975 const uint ob_index = dt->ob_index++;
976 bool use_occlusion_test = dt->use_occlusion_test;
977 /* read/write args */
978 float *ray_depth = dt->ray_depth;
979
980 bool retval = false;
981 if (use_occlusion_test) {
982 if (use_obedit && sctx->use_v3d && XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) {
983 /* Use of occlude geometry in editing mode disabled. */
984 return;
985 }
986
987 if (ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE)) {
988 /* Do not hit objects that are in wire or bounding box
989 * display mode. */
990 return;
991 }
992 }
993
994 switch (ob->type) {
995 case OB_MESH: {
996 Mesh *me = ob->data;
997 bool use_hide = false;
998 if (BKE_object_is_in_editmode(ob)) {
999 if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
1000 /* Operators only update the editmesh looptris of the original mesh. */
1001 BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
1002 retval = raycastEditMesh(sctx,
1003 dt->ray_start,
1004 dt->ray_dir,
1005 ob,
1006 em_orig,
1007 obmat,
1008 ob_index,
1009 use_backface_culling,
1010 ray_depth,
1011 dt->r_loc,
1012 dt->r_no,
1013 dt->r_index,
1014 dt->r_hit_list);
1015 break;
1016 }
1017
1018 BMEditMesh *em = BKE_editmesh_from_object(ob);
1019 if (em->mesh_eval_final) {
1020 me = em->mesh_eval_final;
1021 use_hide = true;
1022 }
1023 }
1024 retval = raycastMesh(sctx,
1025 dt->ray_start,
1026 dt->ray_dir,
1027 ob,
1028 me,
1029 obmat,
1030 ob_index,
1031 use_hide,
1032 use_backface_culling,
1033 ray_depth,
1034 dt->r_loc,
1035 dt->r_no,
1036 dt->r_index,
1037 dt->r_hit_list);
1038 break;
1039 }
1040 case OB_CURVE:
1041 case OB_SURF:
1042 case OB_FONT: {
1043 if (!is_object_active) {
1044 Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
1045 if (mesh_eval) {
1046 retval = raycastMesh(sctx,
1047 dt->ray_start,
1048 dt->ray_dir,
1049 ob,
1050 mesh_eval,
1051 obmat,
1052 ob_index,
1053 false,
1054 use_backface_culling,
1055 ray_depth,
1056 dt->r_loc,
1057 dt->r_no,
1058 dt->r_index,
1059 dt->r_hit_list);
1060 }
1061 }
1062 break;
1063 }
1064 }
1065
1066 if (retval) {
1067 if (dt->r_ob) {
1068 *dt->r_ob = ob;
1069 }
1070 if (dt->r_obmat) {
1071 copy_m4_m4(dt->r_obmat, obmat);
1072 }
1073 dt->ret = true;
1074 }
1075 }
1076
1077 /**
1078 * Main RayCast Function
1079 * ======================
1080 *
1081 * Walks through all objects in the scene to find the `hit` on object surface.
1082 *
1083 * \param sctx: Snap context to store data.
1084 * \param params: Snapping behavior.
1085 *
1086 * Read/Write Args
1087 * ---------------
1088 *
1089 * \param ray_depth: maximum depth allowed for r_co,
1090 * elements deeper than this value will be ignored.
1091 *
1092 * Output Args
1093 * -----------
1094 *
1095 * \param r_loc: Hit location.
1096 * \param r_no: Hit normal (optional).
1097 * \param r_index: Hit index or -1 when no valid index is found.
1098 * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``).
1099 * \param r_ob: Hit object.
1100 * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
1101 * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
1102 */
raycastObjects(SnapObjectContext * sctx,Depsgraph * depsgraph,const struct SnapObjectParams * params,const float ray_start[3],const float ray_dir[3],float * ray_depth,float r_loc[3],float r_no[3],int * r_index,Object ** r_ob,float r_obmat[4][4],ListBase * r_hit_list)1103 static bool raycastObjects(SnapObjectContext *sctx,
1104 Depsgraph *depsgraph,
1105 const struct SnapObjectParams *params,
1106 const float ray_start[3],
1107 const float ray_dir[3],
1108 /* read/write args */
1109 /* Parameters below cannot be const, because they are assigned to a
1110 * non-const variable (readability-non-const-parameter). */
1111 float *ray_depth /* NOLINT */,
1112 /* return args */
1113 float r_loc[3] /* NOLINT */,
1114 float r_no[3] /* NOLINT */,
1115 int *r_index /* NOLINT */,
1116 Object **r_ob,
1117 float r_obmat[4][4],
1118 ListBase *r_hit_list)
1119 {
1120 struct RaycastObjUserData data = {
1121 .ray_start = ray_start,
1122 .ray_dir = ray_dir,
1123 .ob_index = 0,
1124 .ray_depth = ray_depth,
1125 .r_loc = r_loc,
1126 .r_no = r_no,
1127 .r_index = r_index,
1128 .r_ob = r_ob,
1129 .r_obmat = r_obmat,
1130 .r_hit_list = r_hit_list,
1131 .use_occlusion_test = params->use_occlusion_test,
1132 .ret = false,
1133 };
1134
1135 iter_snap_objects(sctx, depsgraph, params, raycast_obj_fn, &data);
1136
1137 return data.ret;
1138 }
1139
1140 /** \} */
1141
1142 /* -------------------------------------------------------------------- */
1143 /** \name Snap Nearest utilities
1144 * \{ */
1145
1146 /* Test BoundBox */
snap_bound_box_check_dist(const float min[3],const float max[3],const float lpmat[4][4],const float win_size[2],const float mval[2],float dist_px_sq)1147 static bool snap_bound_box_check_dist(const float min[3],
1148 const float max[3],
1149 const float lpmat[4][4],
1150 const float win_size[2],
1151 const float mval[2],
1152 float dist_px_sq)
1153 {
1154 /* In vertex and edges you need to get the pixel distance from ray to BoundBox,
1155 * see: T46099, T46816 */
1156
1157 struct DistProjectedAABBPrecalc data_precalc;
1158 dist_squared_to_projected_aabb_precalc(&data_precalc, lpmat, win_size, mval);
1159
1160 bool dummy[3];
1161 float bb_dist_px_sq = dist_squared_to_projected_aabb(&data_precalc, min, max, dummy);
1162
1163 if (bb_dist_px_sq > dist_px_sq) {
1164 return false;
1165 }
1166 return true;
1167 }
1168
cb_mvert_co_get(const int index,const float ** co,const BVHTreeFromMesh * data)1169 static void cb_mvert_co_get(const int index, const float **co, const BVHTreeFromMesh *data)
1170 {
1171 *co = data->vert[index].co;
1172 }
1173
cb_bvert_co_get(const int index,const float ** co,const BMEditMesh * data)1174 static void cb_bvert_co_get(const int index, const float **co, const BMEditMesh *data)
1175 {
1176 BMVert *eve = BM_vert_at_index(data->bm, index);
1177 *co = eve->co;
1178 }
1179
cb_mvert_no_copy(const int index,float r_no[3],const BVHTreeFromMesh * data)1180 static void cb_mvert_no_copy(const int index, float r_no[3], const BVHTreeFromMesh *data)
1181 {
1182 const MVert *vert = data->vert + index;
1183
1184 normal_short_to_float_v3(r_no, vert->no);
1185 }
1186
cb_bvert_no_copy(const int index,float r_no[3],const BMEditMesh * data)1187 static void cb_bvert_no_copy(const int index, float r_no[3], const BMEditMesh *data)
1188 {
1189 BMVert *eve = BM_vert_at_index(data->bm, index);
1190
1191 copy_v3_v3(r_no, eve->no);
1192 }
1193
cb_medge_verts_get(const int index,int v_index[2],const BVHTreeFromMesh * data)1194 static void cb_medge_verts_get(const int index, int v_index[2], const BVHTreeFromMesh *data)
1195 {
1196 const MEdge *edge = &data->edge[index];
1197
1198 v_index[0] = edge->v1;
1199 v_index[1] = edge->v2;
1200 }
1201
cb_bedge_verts_get(const int index,int v_index[2],const BMEditMesh * data)1202 static void cb_bedge_verts_get(const int index, int v_index[2], const BMEditMesh *data)
1203 {
1204 BMEdge *eed = BM_edge_at_index(data->bm, index);
1205
1206 v_index[0] = BM_elem_index_get(eed->v1);
1207 v_index[1] = BM_elem_index_get(eed->v2);
1208 }
1209
cb_mlooptri_edges_get(const int index,int v_index[3],const BVHTreeFromMesh * data)1210 static void cb_mlooptri_edges_get(const int index, int v_index[3], const BVHTreeFromMesh *data)
1211 {
1212 const MEdge *medge = data->edge;
1213 const MLoop *mloop = data->loop;
1214 const MLoopTri *lt = &data->looptri[index];
1215 for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
1216 const MEdge *ed = &medge[mloop[lt->tri[j]].e];
1217 const uint tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
1218 if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) && ELEM(ed->v2, tri_edge[0], tri_edge[1])) {
1219 // printf("real edge found\n");
1220 v_index[j] = mloop[lt->tri[j]].e;
1221 }
1222 else {
1223 v_index[j] = -1;
1224 }
1225 }
1226 }
1227
cb_mlooptri_verts_get(const int index,int v_index[3],const BVHTreeFromMesh * data)1228 static void cb_mlooptri_verts_get(const int index, int v_index[3], const BVHTreeFromMesh *data)
1229 {
1230 const MLoop *loop = data->loop;
1231 const MLoopTri *looptri = &data->looptri[index];
1232
1233 v_index[0] = loop[looptri->tri[0]].v;
1234 v_index[1] = loop[looptri->tri[1]].v;
1235 v_index[2] = loop[looptri->tri[2]].v;
1236 }
1237
test_projected_vert_dist(const struct DistProjectedAABBPrecalc * precalc,const float (* clip_plane)[4],const int clip_plane_len,const bool is_persp,const float co[3],float * dist_px_sq,float r_co[3])1238 static bool test_projected_vert_dist(const struct DistProjectedAABBPrecalc *precalc,
1239 const float (*clip_plane)[4],
1240 const int clip_plane_len,
1241 const bool is_persp,
1242 const float co[3],
1243 float *dist_px_sq,
1244 float r_co[3])
1245 {
1246 if (!isect_point_planes_v3_negated(clip_plane, clip_plane_len, co)) {
1247 return false;
1248 }
1249
1250 float co2d[2] = {
1251 (dot_m4_v3_row_x(precalc->pmat, co) + precalc->pmat[3][0]),
1252 (dot_m4_v3_row_y(precalc->pmat, co) + precalc->pmat[3][1]),
1253 };
1254
1255 if (is_persp) {
1256 float w = mul_project_m4_v3_zfac(precalc->pmat, co);
1257 mul_v2_fl(co2d, 1.0f / w);
1258 }
1259
1260 const float dist_sq = len_squared_v2v2(precalc->mval, co2d);
1261 if (dist_sq < *dist_px_sq) {
1262 copy_v3_v3(r_co, co);
1263 *dist_px_sq = dist_sq;
1264 return true;
1265 }
1266 return false;
1267 }
1268
test_projected_edge_dist(const struct DistProjectedAABBPrecalc * precalc,const float (* clip_plane)[4],const int clip_plane_len,const bool is_persp,const float va[3],const float vb[3],float * dist_px_sq,float r_co[3])1269 static bool test_projected_edge_dist(const struct DistProjectedAABBPrecalc *precalc,
1270 const float (*clip_plane)[4],
1271 const int clip_plane_len,
1272 const bool is_persp,
1273 const float va[3],
1274 const float vb[3],
1275 float *dist_px_sq,
1276 float r_co[3])
1277 {
1278 float near_co[3], lambda;
1279 if (!isect_ray_line_v3(precalc->ray_origin, precalc->ray_direction, va, vb, &lambda)) {
1280 copy_v3_v3(near_co, va);
1281 }
1282 else {
1283 if (lambda <= 0.0f) {
1284 copy_v3_v3(near_co, va);
1285 }
1286 else if (lambda >= 1.0f) {
1287 copy_v3_v3(near_co, vb);
1288 }
1289 else {
1290 interp_v3_v3v3(near_co, va, vb, lambda);
1291 }
1292 }
1293
1294 return test_projected_vert_dist(
1295 precalc, clip_plane, clip_plane_len, is_persp, near_co, dist_px_sq, r_co);
1296 }
1297
1298 /** \} */
1299
1300 /* -------------------------------------------------------------------- */
1301 /** \name Walk DFS
1302 * \{ */
1303
1304 typedef void (*Nearest2DGetVertCoCallback)(const int index, const float **co, void *data);
1305 typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, const int v_index[2], void *data);
1306 typedef void (*Nearest2DGetTriVertsCallback)(const int index, const int v_index[3], void *data);
1307 /* Equal the previous one */
1308 typedef void (*Nearest2DGetTriEdgesCallback)(const int index, const int e_index[3], void *data);
1309 typedef void (*Nearest2DCopyVertNoCallback)(const int index, const float r_no[3], void *data);
1310
1311 typedef struct Nearest2dUserData {
1312 void *userdata;
1313 Nearest2DGetVertCoCallback get_vert_co;
1314 Nearest2DGetEdgeVertsCallback get_edge_verts_index;
1315 Nearest2DGetTriVertsCallback get_tri_verts_index;
1316 Nearest2DGetTriEdgesCallback get_tri_edges_index;
1317 Nearest2DCopyVertNoCallback copy_vert_no;
1318
1319 bool is_persp;
1320 bool use_backface_culling;
1321 } Nearest2dUserData;
1322
cb_snap_vert(void * userdata,int index,const struct DistProjectedAABBPrecalc * precalc,const float (* clip_plane)[4],const int clip_plane_len,BVHTreeNearest * nearest)1323 static void cb_snap_vert(void *userdata,
1324 int index,
1325 const struct DistProjectedAABBPrecalc *precalc,
1326 const float (*clip_plane)[4],
1327 const int clip_plane_len,
1328 BVHTreeNearest *nearest)
1329 {
1330 struct Nearest2dUserData *data = userdata;
1331
1332 const float *co;
1333 data->get_vert_co(index, &co, data->userdata);
1334
1335 if (test_projected_vert_dist(precalc,
1336 clip_plane,
1337 clip_plane_len,
1338 data->is_persp,
1339 co,
1340 &nearest->dist_sq,
1341 nearest->co)) {
1342 data->copy_vert_no(index, nearest->no, data->userdata);
1343 nearest->index = index;
1344 }
1345 }
1346
cb_snap_edge(void * userdata,int index,const struct DistProjectedAABBPrecalc * precalc,const float (* clip_plane)[4],const int clip_plane_len,BVHTreeNearest * nearest)1347 static void cb_snap_edge(void *userdata,
1348 int index,
1349 const struct DistProjectedAABBPrecalc *precalc,
1350 const float (*clip_plane)[4],
1351 const int clip_plane_len,
1352 BVHTreeNearest *nearest)
1353 {
1354 struct Nearest2dUserData *data = userdata;
1355
1356 int vindex[2];
1357 data->get_edge_verts_index(index, vindex, data->userdata);
1358
1359 const float *v_pair[2];
1360 data->get_vert_co(vindex[0], &v_pair[0], data->userdata);
1361 data->get_vert_co(vindex[1], &v_pair[1], data->userdata);
1362
1363 if (test_projected_edge_dist(precalc,
1364 clip_plane,
1365 clip_plane_len,
1366 data->is_persp,
1367 v_pair[0],
1368 v_pair[1],
1369 &nearest->dist_sq,
1370 nearest->co)) {
1371 sub_v3_v3v3(nearest->no, v_pair[0], v_pair[1]);
1372 nearest->index = index;
1373 }
1374 }
1375
cb_snap_edge_verts(void * userdata,int index,const struct DistProjectedAABBPrecalc * precalc,const float (* clip_plane)[4],const int clip_plane_len,BVHTreeNearest * nearest)1376 static void cb_snap_edge_verts(void *userdata,
1377 int index,
1378 const struct DistProjectedAABBPrecalc *precalc,
1379 const float (*clip_plane)[4],
1380 const int clip_plane_len,
1381 BVHTreeNearest *nearest)
1382 {
1383 struct Nearest2dUserData *data = userdata;
1384
1385 int vindex[2];
1386 data->get_edge_verts_index(index, vindex, data->userdata);
1387
1388 for (int i = 2; i--;) {
1389 if (vindex[i] == nearest->index) {
1390 continue;
1391 }
1392 cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
1393 }
1394 }
1395
cb_snap_tri_edges(void * userdata,int index,const struct DistProjectedAABBPrecalc * precalc,const float (* clip_plane)[4],const int clip_plane_len,BVHTreeNearest * nearest)1396 static void cb_snap_tri_edges(void *userdata,
1397 int index,
1398 const struct DistProjectedAABBPrecalc *precalc,
1399 const float (*clip_plane)[4],
1400 const int clip_plane_len,
1401 BVHTreeNearest *nearest)
1402 {
1403 struct Nearest2dUserData *data = userdata;
1404
1405 if (data->use_backface_culling) {
1406 int vindex[3];
1407 data->get_tri_verts_index(index, vindex, data->userdata);
1408
1409 const float *t0, *t1, *t2;
1410 data->get_vert_co(vindex[0], &t0, data->userdata);
1411 data->get_vert_co(vindex[1], &t1, data->userdata);
1412 data->get_vert_co(vindex[2], &t2, data->userdata);
1413 float dummy[3];
1414 if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
1415 return;
1416 }
1417 }
1418
1419 int eindex[3];
1420 data->get_tri_edges_index(index, eindex, data->userdata);
1421 for (int i = 3; i--;) {
1422 if (eindex[i] != -1) {
1423 if (eindex[i] == nearest->index) {
1424 continue;
1425 }
1426 cb_snap_edge(userdata, eindex[i], precalc, clip_plane, clip_plane_len, nearest);
1427 }
1428 }
1429 }
1430
cb_snap_tri_verts(void * userdata,int index,const struct DistProjectedAABBPrecalc * precalc,const float (* clip_plane)[4],const int clip_plane_len,BVHTreeNearest * nearest)1431 static void cb_snap_tri_verts(void *userdata,
1432 int index,
1433 const struct DistProjectedAABBPrecalc *precalc,
1434 const float (*clip_plane)[4],
1435 const int clip_plane_len,
1436 BVHTreeNearest *nearest)
1437 {
1438 struct Nearest2dUserData *data = userdata;
1439
1440 int vindex[3];
1441 data->get_tri_verts_index(index, vindex, data->userdata);
1442
1443 if (data->use_backface_culling) {
1444 const float *t0, *t1, *t2;
1445 data->get_vert_co(vindex[0], &t0, data->userdata);
1446 data->get_vert_co(vindex[1], &t1, data->userdata);
1447 data->get_vert_co(vindex[2], &t2, data->userdata);
1448 float dummy[3];
1449 if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
1450 return;
1451 }
1452 }
1453
1454 for (int i = 3; i--;) {
1455 if (vindex[i] == nearest->index) {
1456 continue;
1457 }
1458 cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
1459 }
1460 }
1461
1462 /** \} */
1463
1464 /* -------------------------------------------------------------------- */
1465 /** \name Internal Object Snapping API
1466 * \{ */
1467
snap_mesh_polygon(SnapObjectContext * sctx,SnapData * snapdata,Object * ob,const float obmat[4][4],bool use_backface_culling,float * dist_px,float r_loc[3],float r_no[3],int * r_index)1468 static short snap_mesh_polygon(SnapObjectContext *sctx,
1469 SnapData *snapdata,
1470 Object *ob,
1471 const float obmat[4][4],
1472 bool use_backface_culling,
1473 /* read/write args */
1474 float *dist_px,
1475 /* return args */
1476 float r_loc[3],
1477 float r_no[3],
1478 int *r_index)
1479 {
1480 short elem = 0;
1481
1482 float lpmat[4][4];
1483 mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
1484
1485 struct DistProjectedAABBPrecalc neasrest_precalc;
1486 dist_squared_to_projected_aabb_precalc(
1487 &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
1488
1489 float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
1490 transpose_m4_m4(tobmat, obmat);
1491 for (int i = snapdata->clip_plane_len; i--;) {
1492 mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
1493 }
1494
1495 Nearest2dUserData nearest2d = {
1496 .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
1497 .use_backface_culling = use_backface_culling,
1498 };
1499
1500 BVHTreeNearest nearest = {
1501 .index = -1,
1502 .dist_sq = square_f(*dist_px),
1503 };
1504
1505 SnapObjectData *sod = snap_object_data_lookup(sctx, ob);
1506
1507 BLI_assert(sod != NULL);
1508
1509 if (sod->type == SNAP_MESH) {
1510 BVHTreeFromMesh *treedata = &sod->treedata_mesh;
1511
1512 nearest2d.userdata = treedata;
1513 nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
1514 nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
1515 nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
1516
1517 const MPoly *mp = &sod->poly[*r_index];
1518 const MLoop *ml = &treedata->loop[mp->loopstart];
1519 if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
1520 elem = SCE_SNAP_MODE_EDGE;
1521 BLI_assert(treedata->edge != NULL);
1522 for (int i = mp->totloop; i--; ml++) {
1523 cb_snap_edge(&nearest2d,
1524 ml->e,
1525 &neasrest_precalc,
1526 clip_planes_local,
1527 snapdata->clip_plane_len,
1528 &nearest);
1529 }
1530 }
1531 else {
1532 elem = SCE_SNAP_MODE_VERTEX;
1533 for (int i = mp->totloop; i--; ml++) {
1534 cb_snap_vert(&nearest2d,
1535 ml->v,
1536 &neasrest_precalc,
1537 clip_planes_local,
1538 snapdata->clip_plane_len,
1539 &nearest);
1540 }
1541 }
1542 }
1543 else {
1544 BLI_assert(sod->type == SNAP_EDIT_MESH);
1545 BMEditMesh *em = sod->treedata_editmesh.em;
1546
1547 nearest2d.userdata = em;
1548 nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
1549 nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
1550 nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
1551
1552 BM_mesh_elem_table_ensure(em->bm, BM_FACE);
1553 BMFace *f = BM_face_at_index(em->bm, *r_index);
1554 BMLoop *l_iter, *l_first;
1555 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1556 if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
1557 elem = SCE_SNAP_MODE_EDGE;
1558 BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_EDGE);
1559 BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE);
1560 do {
1561 cb_snap_edge(&nearest2d,
1562 BM_elem_index_get(l_iter->e),
1563 &neasrest_precalc,
1564 clip_planes_local,
1565 snapdata->clip_plane_len,
1566 &nearest);
1567 } while ((l_iter = l_iter->next) != l_first);
1568 }
1569 else {
1570 elem = SCE_SNAP_MODE_VERTEX;
1571 BM_mesh_elem_index_ensure(em->bm, BM_VERT);
1572 BM_mesh_elem_table_ensure(em->bm, BM_VERT);
1573 do {
1574 cb_snap_vert(&nearest2d,
1575 BM_elem_index_get(l_iter->v),
1576 &neasrest_precalc,
1577 clip_planes_local,
1578 snapdata->clip_plane_len,
1579 &nearest);
1580 } while ((l_iter = l_iter->next) != l_first);
1581 }
1582 }
1583
1584 if (nearest.index != -1) {
1585 *dist_px = sqrtf(nearest.dist_sq);
1586
1587 copy_v3_v3(r_loc, nearest.co);
1588 mul_m4_v3(obmat, r_loc);
1589
1590 if (r_no) {
1591 float imat[4][4];
1592 invert_m4_m4(imat, obmat);
1593
1594 copy_v3_v3(r_no, nearest.no);
1595 mul_transposed_mat3_m4_v3(imat, r_no);
1596 normalize_v3(r_no);
1597 }
1598
1599 *r_index = nearest.index;
1600 return elem;
1601 }
1602
1603 return 0;
1604 }
1605
snap_mesh_edge_verts_mixed(SnapObjectContext * sctx,SnapData * snapdata,Object * ob,const float obmat[4][4],float original_dist_px,const float prev_co[3],bool use_backface_culling,float * dist_px,float r_loc[3],float r_no[3],int * r_index)1606 static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
1607 SnapData *snapdata,
1608 Object *ob,
1609 const float obmat[4][4],
1610 float original_dist_px,
1611 const float prev_co[3],
1612 bool use_backface_culling,
1613 /* read/write args */
1614 float *dist_px,
1615 /* return args */
1616 float r_loc[3],
1617 float r_no[3],
1618 int *r_index)
1619 {
1620 short elem = SCE_SNAP_MODE_EDGE;
1621
1622 if (ob->type != OB_MESH) {
1623 return elem;
1624 }
1625
1626 SnapObjectData *sod = snap_object_data_lookup(sctx, ob);
1627
1628 BLI_assert(sod != NULL);
1629
1630 Nearest2dUserData nearest2d;
1631 {
1632 nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
1633 nearest2d.use_backface_culling = use_backface_culling;
1634 if (sod->type == SNAP_MESH) {
1635 nearest2d.userdata = &sod->treedata_mesh;
1636 nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
1637 nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
1638 nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
1639 }
1640 else {
1641 BLI_assert(sod->type == SNAP_EDIT_MESH);
1642 nearest2d.userdata = sod->treedata_editmesh.em;
1643 nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
1644 nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
1645 nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
1646 }
1647 }
1648
1649 int vindex[2];
1650 nearest2d.get_edge_verts_index(*r_index, vindex, nearest2d.userdata);
1651
1652 const float *v_pair[2];
1653 nearest2d.get_vert_co(vindex[0], &v_pair[0], nearest2d.userdata);
1654 nearest2d.get_vert_co(vindex[1], &v_pair[1], nearest2d.userdata);
1655
1656 struct DistProjectedAABBPrecalc neasrest_precalc;
1657 {
1658 float lpmat[4][4];
1659 mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
1660
1661 dist_squared_to_projected_aabb_precalc(
1662 &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
1663 }
1664
1665 BVHTreeNearest nearest = {
1666 .index = -1,
1667 .dist_sq = square_f(original_dist_px),
1668 };
1669
1670 float lambda;
1671 if (!isect_ray_line_v3(neasrest_precalc.ray_origin,
1672 neasrest_precalc.ray_direction,
1673 v_pair[0],
1674 v_pair[1],
1675 &lambda)) {
1676 /* do nothing */
1677 }
1678 else {
1679 short snap_to_flag = snapdata->snap_to_flag;
1680 int e_mode_len = ((snap_to_flag & SCE_SNAP_MODE_EDGE) != 0) +
1681 ((snap_to_flag & SCE_SNAP_MODE_VERTEX) != 0) +
1682 ((snap_to_flag & SCE_SNAP_MODE_EDGE_MIDPOINT) != 0);
1683
1684 float range = 1.0f / (2 * e_mode_len - 1);
1685 if (snap_to_flag & SCE_SNAP_MODE_VERTEX) {
1686 if (lambda < (range) || (1.0f - range) < lambda) {
1687 int v_id = lambda < 0.5f ? 0 : 1;
1688
1689 if (test_projected_vert_dist(&neasrest_precalc,
1690 NULL,
1691 0,
1692 nearest2d.is_persp,
1693 v_pair[v_id],
1694 &nearest.dist_sq,
1695 nearest.co)) {
1696 nearest.index = vindex[v_id];
1697 elem = SCE_SNAP_MODE_VERTEX;
1698 if (r_no) {
1699 float imat[4][4];
1700 invert_m4_m4(imat, obmat);
1701 nearest2d.copy_vert_no(vindex[v_id], r_no, nearest2d.userdata);
1702 mul_transposed_mat3_m4_v3(imat, r_no);
1703 normalize_v3(r_no);
1704 }
1705 }
1706 }
1707 }
1708
1709 if (snap_to_flag & SCE_SNAP_MODE_EDGE_MIDPOINT) {
1710 range *= e_mode_len - 1;
1711 if ((range) < lambda && lambda < (1.0f - range)) {
1712 float vmid[3];
1713 mid_v3_v3v3(vmid, v_pair[0], v_pair[1]);
1714
1715 if (test_projected_vert_dist(&neasrest_precalc,
1716 NULL,
1717 0,
1718 nearest2d.is_persp,
1719 vmid,
1720 &nearest.dist_sq,
1721 nearest.co)) {
1722 nearest.index = *r_index;
1723 elem = SCE_SNAP_MODE_EDGE_MIDPOINT;
1724 }
1725 }
1726 }
1727
1728 if (prev_co && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
1729 float v_near[3], va_g[3], vb_g[3];
1730
1731 mul_v3_m4v3(va_g, obmat, v_pair[0]);
1732 mul_v3_m4v3(vb_g, obmat, v_pair[1]);
1733 lambda = line_point_factor_v3(prev_co, va_g, vb_g);
1734
1735 if (IN_RANGE(lambda, 0.0f, 1.0f)) {
1736 interp_v3_v3v3(v_near, va_g, vb_g, lambda);
1737
1738 if (len_squared_v3v3(prev_co, v_near) > FLT_EPSILON) {
1739 dist_squared_to_projected_aabb_precalc(
1740 &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
1741
1742 if (test_projected_vert_dist(&neasrest_precalc,
1743 NULL,
1744 0,
1745 nearest2d.is_persp,
1746 v_near,
1747 &nearest.dist_sq,
1748 nearest.co)) {
1749 nearest.index = *r_index;
1750 elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR;
1751 }
1752 }
1753 }
1754 }
1755 }
1756
1757 if (nearest.index != -1) {
1758 *dist_px = sqrtf(nearest.dist_sq);
1759
1760 copy_v3_v3(r_loc, nearest.co);
1761 if (elem != SCE_SNAP_MODE_EDGE_PERPENDICULAR) {
1762 mul_m4_v3(obmat, r_loc);
1763 }
1764
1765 *r_index = nearest.index;
1766 }
1767
1768 return elem;
1769 }
1770
snapArmature(SnapData * snapdata,Object * ob,const float obmat[4][4],bool use_obedit,float * dist_px,float r_loc[3],float * UNUSED (r_no),int * r_index)1771 static short snapArmature(SnapData *snapdata,
1772 Object *ob,
1773 const float obmat[4][4],
1774 bool use_obedit,
1775 /* read/write args */
1776 float *dist_px,
1777 /* return args */
1778 float r_loc[3],
1779 float *UNUSED(r_no),
1780 int *r_index)
1781 {
1782 short retval = 0;
1783
1784 if (snapdata->snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */
1785 return retval;
1786 }
1787
1788 float lpmat[4][4], dist_px_sq = square_f(*dist_px);
1789 mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
1790
1791 struct DistProjectedAABBPrecalc neasrest_precalc;
1792 dist_squared_to_projected_aabb_precalc(
1793 &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
1794
1795 use_obedit = use_obedit && BKE_object_is_in_editmode(ob);
1796
1797 if (use_obedit == false) {
1798 /* Test BoundBox */
1799 BoundBox *bb = BKE_armature_boundbox_get(ob);
1800 if (bb && !snap_bound_box_check_dist(
1801 bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
1802 return retval;
1803 }
1804 }
1805
1806 float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
1807 transpose_m4_m4(tobmat, obmat);
1808 for (int i = snapdata->clip_plane_len; i--;) {
1809 mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
1810 }
1811
1812 bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
1813
1814 bArmature *arm = ob->data;
1815 if (arm->edbo) {
1816 LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
1817 if (eBone->layer & arm->layer) {
1818 /* skip hidden or moving (selected) bones */
1819 if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
1820 bool has_vert_snap = false;
1821
1822 if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
1823 has_vert_snap = test_projected_vert_dist(&neasrest_precalc,
1824 clip_planes_local,
1825 snapdata->clip_plane_len,
1826 is_persp,
1827 eBone->head,
1828 &dist_px_sq,
1829 r_loc);
1830 has_vert_snap |= test_projected_vert_dist(&neasrest_precalc,
1831 clip_planes_local,
1832 snapdata->clip_plane_len,
1833 is_persp,
1834 eBone->tail,
1835 &dist_px_sq,
1836 r_loc);
1837
1838 if (has_vert_snap) {
1839 retval = SCE_SNAP_MODE_VERTEX;
1840 }
1841 }
1842 if (!has_vert_snap && snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
1843 if (test_projected_edge_dist(&neasrest_precalc,
1844 clip_planes_local,
1845 snapdata->clip_plane_len,
1846 is_persp,
1847 eBone->head,
1848 eBone->tail,
1849 &dist_px_sq,
1850 r_loc)) {
1851 retval = SCE_SNAP_MODE_EDGE;
1852 }
1853 }
1854 }
1855 }
1856 }
1857 }
1858 else if (ob->pose && ob->pose->chanbase.first) {
1859 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
1860 Bone *bone = pchan->bone;
1861 /* skip hidden bones */
1862 if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
1863 bool has_vert_snap = false;
1864 const float *head_vec = pchan->pose_head;
1865 const float *tail_vec = pchan->pose_tail;
1866
1867 if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
1868 has_vert_snap = test_projected_vert_dist(&neasrest_precalc,
1869 clip_planes_local,
1870 snapdata->clip_plane_len,
1871 is_persp,
1872 head_vec,
1873 &dist_px_sq,
1874 r_loc);
1875 has_vert_snap |= test_projected_vert_dist(&neasrest_precalc,
1876 clip_planes_local,
1877 snapdata->clip_plane_len,
1878 is_persp,
1879 tail_vec,
1880 &dist_px_sq,
1881 r_loc);
1882
1883 if (has_vert_snap) {
1884 retval = SCE_SNAP_MODE_VERTEX;
1885 }
1886 }
1887 if (!has_vert_snap && snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
1888 if (test_projected_edge_dist(&neasrest_precalc,
1889 clip_planes_local,
1890 snapdata->clip_plane_len,
1891 is_persp,
1892 head_vec,
1893 tail_vec,
1894 &dist_px_sq,
1895 r_loc)) {
1896 retval = SCE_SNAP_MODE_EDGE;
1897 }
1898 }
1899 }
1900 }
1901 }
1902
1903 if (retval) {
1904 *dist_px = sqrtf(dist_px_sq);
1905 mul_m4_v3(obmat, r_loc);
1906 if (r_index) {
1907 /* Does not support index. */
1908 *r_index = -1;
1909 }
1910 return retval;
1911 }
1912
1913 return 0;
1914 }
1915
snapCurve(SnapData * snapdata,Object * ob,const float obmat[4][4],bool use_obedit,float * dist_px,float r_loc[3],float * UNUSED (r_no),int * r_index)1916 static short snapCurve(SnapData *snapdata,
1917 Object *ob,
1918 const float obmat[4][4],
1919 bool use_obedit,
1920 /* read/write args */
1921 float *dist_px,
1922 /* return args */
1923 float r_loc[3],
1924 float *UNUSED(r_no),
1925 int *r_index)
1926 {
1927 bool has_snap = false;
1928
1929 /* only vertex snapping mode (eg control points and handles) supported for now) */
1930 if ((snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) {
1931 return 0;
1932 }
1933
1934 Curve *cu = ob->data;
1935 float dist_px_sq = square_f(*dist_px);
1936
1937 float lpmat[4][4];
1938 mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
1939
1940 struct DistProjectedAABBPrecalc neasrest_precalc;
1941 dist_squared_to_projected_aabb_precalc(
1942 &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
1943
1944 use_obedit = use_obedit && BKE_object_is_in_editmode(ob);
1945
1946 if (use_obedit == false) {
1947 /* Test BoundBox */
1948 BoundBox *bb = BKE_curve_boundbox_get(ob);
1949 if (bb && !snap_bound_box_check_dist(
1950 bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
1951 return 0;
1952 }
1953 }
1954
1955 float tobmat[4][4];
1956 transpose_m4_m4(tobmat, obmat);
1957
1958 float(*clip_planes)[4] = snapdata->clip_plane;
1959 int clip_plane_len = snapdata->clip_plane_len;
1960
1961 if (snapdata->has_occlusion_plane) {
1962 /* We snap to vertices even if coccluded. */
1963 clip_planes++;
1964 clip_plane_len--;
1965 }
1966
1967 float clip_planes_local[MAX_CLIPPLANE_LEN][4];
1968 for (int i = clip_plane_len; i--;) {
1969 mul_v4_m4v4(clip_planes_local[i], tobmat, clip_planes[i]);
1970 }
1971
1972 bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
1973
1974 for (Nurb *nu = (use_obedit ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
1975 for (int u = 0; u < nu->pntsu; u++) {
1976 if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
1977 if (use_obedit) {
1978 if (nu->bezt) {
1979 /* don't snap to selected (moving) or hidden */
1980 if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
1981 continue;
1982 }
1983 has_snap |= test_projected_vert_dist(&neasrest_precalc,
1984 clip_planes_local,
1985 clip_plane_len,
1986 is_persp,
1987 nu->bezt[u].vec[1],
1988 &dist_px_sq,
1989 r_loc);
1990 /* Don't snap if handle is selected (moving),
1991 * or if it is aligning to a moving handle. */
1992 if (!(nu->bezt[u].f1 & SELECT) &&
1993 !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) {
1994 has_snap |= test_projected_vert_dist(&neasrest_precalc,
1995 clip_planes_local,
1996 clip_plane_len,
1997 is_persp,
1998 nu->bezt[u].vec[0],
1999 &dist_px_sq,
2000 r_loc);
2001 }
2002 if (!(nu->bezt[u].f3 & SELECT) &&
2003 !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) {
2004 has_snap |= test_projected_vert_dist(&neasrest_precalc,
2005 clip_planes_local,
2006 clip_plane_len,
2007 is_persp,
2008 nu->bezt[u].vec[2],
2009 &dist_px_sq,
2010 r_loc);
2011 }
2012 }
2013 else {
2014 /* don't snap to selected (moving) or hidden */
2015 if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
2016 continue;
2017 }
2018 has_snap |= test_projected_vert_dist(&neasrest_precalc,
2019 clip_planes_local,
2020 clip_plane_len,
2021 is_persp,
2022 nu->bp[u].vec,
2023 &dist_px_sq,
2024 r_loc);
2025 }
2026 }
2027 else {
2028 /* curve is not visible outside editmode if nurb length less than two */
2029 if (nu->pntsu > 1) {
2030 if (nu->bezt) {
2031 has_snap |= test_projected_vert_dist(&neasrest_precalc,
2032 clip_planes_local,
2033 clip_plane_len,
2034 is_persp,
2035 nu->bezt[u].vec[1],
2036 &dist_px_sq,
2037 r_loc);
2038 }
2039 else {
2040 has_snap |= test_projected_vert_dist(&neasrest_precalc,
2041 clip_planes_local,
2042 clip_plane_len,
2043 is_persp,
2044 nu->bp[u].vec,
2045 &dist_px_sq,
2046 r_loc);
2047 }
2048 }
2049 }
2050 }
2051 }
2052 }
2053 if (has_snap) {
2054 *dist_px = sqrtf(dist_px_sq);
2055 mul_m4_v3(obmat, r_loc);
2056 if (r_index) {
2057 /* Does not support index yet. */
2058 *r_index = -1;
2059 }
2060 return SCE_SNAP_MODE_VERTEX;
2061 }
2062
2063 return 0;
2064 }
2065
2066 /* may extend later (for now just snaps to empty center) */
snap_object_center(SnapData * snapdata,Object * ob,const float obmat[4][4],float * dist_px,float r_loc[3],float * UNUSED (r_no),int * r_index)2067 static short snap_object_center(SnapData *snapdata,
2068 Object *ob,
2069 const float obmat[4][4],
2070 /* read/write args */
2071 float *dist_px,
2072 /* return args */
2073 float r_loc[3],
2074 float *UNUSED(r_no),
2075 int *r_index)
2076 {
2077 short retval = 0;
2078
2079 if (ob->transflag & OB_DUPLI) {
2080 return retval;
2081 }
2082
2083 /* for now only vertex supported */
2084 if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
2085 struct DistProjectedAABBPrecalc neasrest_precalc;
2086 dist_squared_to_projected_aabb_precalc(
2087 &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
2088
2089 float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
2090 transpose_m4_m4(tobmat, obmat);
2091 for (int i = snapdata->clip_plane_len; i--;) {
2092 mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
2093 }
2094
2095 bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
2096 float dist_px_sq = square_f(*dist_px);
2097 float co[3];
2098 copy_v3_v3(co, obmat[3]);
2099 if (test_projected_vert_dist(&neasrest_precalc,
2100 clip_planes_local,
2101 snapdata->clip_plane_len,
2102 is_persp,
2103 co,
2104 &dist_px_sq,
2105 r_loc)) {
2106 *dist_px = sqrtf(dist_px_sq);
2107 retval = SCE_SNAP_MODE_VERTEX;
2108 }
2109 }
2110
2111 if (retval) {
2112 if (r_index) {
2113 /* Does not support index. */
2114 *r_index = -1;
2115 }
2116 return retval;
2117 }
2118
2119 return 0;
2120 }
2121
snapCamera(const SnapObjectContext * sctx,SnapData * snapdata,Object * object,float obmat[4][4],float * dist_px,float r_loc[3],float * r_no,int * r_index)2122 static short snapCamera(const SnapObjectContext *sctx,
2123 SnapData *snapdata,
2124 Object *object,
2125 float obmat[4][4],
2126 /* read/write args */
2127 float *dist_px,
2128 /* return args */
2129 float r_loc[3],
2130 float *r_no,
2131 int *r_index)
2132 {
2133 short retval = 0;
2134
2135 Scene *scene = sctx->scene;
2136
2137 bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
2138 float dist_px_sq = square_f(*dist_px);
2139
2140 float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
2141 MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
2142 MovieTracking *tracking;
2143
2144 if (clip == NULL) {
2145 return snap_object_center(snapdata, object, obmat, dist_px, r_loc, r_no, r_index);
2146 }
2147 if (object->transflag & OB_DUPLI) {
2148 return retval;
2149 }
2150
2151 tracking = &clip->tracking;
2152
2153 BKE_tracking_get_camera_object_matrix(object, orig_camera_mat);
2154
2155 invert_m4_m4(orig_camera_imat, orig_camera_mat);
2156 invert_m4_m4(imat, obmat);
2157
2158 if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
2159 struct DistProjectedAABBPrecalc neasrest_precalc;
2160 dist_squared_to_projected_aabb_precalc(
2161 &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
2162
2163 MovieTrackingObject *tracking_object;
2164 for (tracking_object = tracking->objects.first; tracking_object;
2165 tracking_object = tracking_object->next) {
2166 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
2167 MovieTrackingTrack *track;
2168 float reconstructed_camera_mat[4][4], reconstructed_camera_imat[4][4];
2169 float(*vertex_obmat)[4];
2170
2171 if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
2172 BKE_tracking_camera_get_reconstructed_interpolate(
2173 tracking, tracking_object, CFRA, reconstructed_camera_mat);
2174
2175 invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
2176 }
2177
2178 for (track = tracksbase->first; track; track = track->next) {
2179 float bundle_pos[3];
2180
2181 if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
2182 continue;
2183 }
2184
2185 copy_v3_v3(bundle_pos, track->bundle_pos);
2186 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2187 vertex_obmat = orig_camera_mat;
2188 }
2189 else {
2190 mul_m4_v3(reconstructed_camera_imat, bundle_pos);
2191 vertex_obmat = obmat;
2192 }
2193
2194 mul_m4_v3(vertex_obmat, bundle_pos);
2195 if (test_projected_vert_dist(&neasrest_precalc,
2196 snapdata->clip_plane,
2197 snapdata->clip_plane_len,
2198 is_persp,
2199 bundle_pos,
2200 &dist_px_sq,
2201 r_loc)) {
2202 retval = SCE_SNAP_MODE_VERTEX;
2203 }
2204 }
2205 }
2206 }
2207
2208 if (retval) {
2209 *dist_px = sqrtf(dist_px_sq);
2210 if (r_index) {
2211 /* Does not support index. */
2212 *r_index = -1;
2213 }
2214 return retval;
2215 }
2216
2217 return 0;
2218 }
2219
snapMesh(SnapObjectContext * sctx,SnapData * snapdata,Object * ob,Mesh * me,const float obmat[4][4],bool use_backface_culling,float * dist_px,float r_loc[3],float r_no[3],int * r_index)2220 static short snapMesh(SnapObjectContext *sctx,
2221 SnapData *snapdata,
2222 Object *ob,
2223 Mesh *me,
2224 const float obmat[4][4],
2225 bool use_backface_culling,
2226 /* read/write args */
2227 float *dist_px,
2228 /* return args */
2229 float r_loc[3],
2230 float r_no[3],
2231 int *r_index)
2232 {
2233 BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE);
2234
2235 if ((snapdata->snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
2236 if (me->totvert == 0) {
2237 return 0;
2238 }
2239 }
2240 else {
2241 if (me->totedge == 0) {
2242 return 0;
2243 }
2244 }
2245
2246 float lpmat[4][4];
2247 mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
2248
2249 float dist_px_sq = square_f(*dist_px);
2250
2251 /* Test BoundBox */
2252 BoundBox *bb = BKE_mesh_boundbox_get(ob);
2253 if (bb && !snap_bound_box_check_dist(
2254 bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
2255 return 0;
2256 }
2257
2258 SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob);
2259
2260 BVHTreeFromMesh *treedata, dummy_treedata;
2261 treedata = &sod->treedata_mesh;
2262
2263 /* The tree is owned by the Mesh and may have been freed since we last used! */
2264 if (treedata->cached && treedata->tree &&
2265 !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) {
2266 free_bvhtree_from_mesh(treedata);
2267 }
2268 if (sod->cached[0] && sod->bvhtree[0] &&
2269 !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[0])) {
2270 sod->bvhtree[0] = NULL;
2271 }
2272 if (sod->cached[1] && sod->bvhtree[1] &&
2273 !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[1])) {
2274 sod->bvhtree[1] = NULL;
2275 }
2276
2277 if (sod->has_looptris && treedata->tree == NULL) {
2278 BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4);
2279 sod->has_looptris = (treedata->tree != NULL);
2280 if (sod->has_looptris) {
2281 /* Make sure that the array of edges is referenced in the callbacks. */
2282 treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
2283 }
2284 }
2285 if (sod->has_loose_edge && sod->bvhtree[0] == NULL) {
2286 sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2);
2287 sod->has_loose_edge = sod->bvhtree[0] != NULL;
2288 sod->cached[0] = dummy_treedata.cached;
2289
2290 if (sod->has_loose_edge) {
2291 BLI_assert(treedata->vert_allocated == false);
2292 treedata->vert = dummy_treedata.vert;
2293 treedata->vert_allocated = dummy_treedata.vert_allocated;
2294
2295 BLI_assert(treedata->edge_allocated == false);
2296 treedata->edge = dummy_treedata.edge;
2297 treedata->edge_allocated = dummy_treedata.edge_allocated;
2298 }
2299 }
2300 if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
2301 if (sod->has_loose_vert && sod->bvhtree[1] == NULL) {
2302 sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2);
2303 sod->has_loose_vert = sod->bvhtree[1] != NULL;
2304 sod->cached[1] = dummy_treedata.cached;
2305
2306 if (sod->has_loose_vert) {
2307 BLI_assert(treedata->vert_allocated == false);
2308 treedata->vert = dummy_treedata.vert;
2309 treedata->vert_allocated = dummy_treedata.vert_allocated;
2310 }
2311 }
2312 }
2313 else {
2314 /* Not necessary, just to keep the data more consistent. */
2315 sod->has_loose_vert = false;
2316 }
2317
2318 /* Update pointers. */
2319 if (treedata->vert_allocated == false) {
2320 treedata->vert = me->mvert; /* CustomData_get_layer(&me->vdata, CD_MVERT);? */
2321 }
2322 if (treedata->tree || sod->bvhtree[0]) {
2323 if (treedata->edge_allocated == false) {
2324 /* If raycast has been executed before, `treedata->edge` can be NULL. */
2325 treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
2326 }
2327 if (treedata->loop && treedata->loop_allocated == false) {
2328 treedata->loop = me->mloop; /* CustomData_get_layer(&me->edata, CD_MLOOP);? */
2329 }
2330 if (treedata->looptri && treedata->looptri_allocated == false) {
2331 treedata->looptri = BKE_mesh_runtime_looptri_ensure(me);
2332 }
2333 }
2334
2335 Nearest2dUserData nearest2d = {
2336 .userdata = treedata,
2337 .get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get,
2338 .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get,
2339 .get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get,
2340 .get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get,
2341 .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy,
2342 .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
2343 .use_backface_culling = use_backface_culling,
2344 };
2345
2346 BVHTreeNearest nearest = {
2347 .index = -1,
2348 .dist_sq = dist_px_sq,
2349 };
2350 int last_index = nearest.index;
2351 short elem = SCE_SNAP_MODE_VERTEX;
2352
2353 float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
2354 transpose_m4_m4(tobmat, obmat);
2355 for (int i = snapdata->clip_plane_len; i--;) {
2356 mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
2357 }
2358
2359 if (sod->bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
2360 /* snap to loose verts */
2361 BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
2362 lpmat,
2363 snapdata->win_size,
2364 snapdata->mval,
2365 clip_planes_local,
2366 snapdata->clip_plane_len,
2367 &nearest,
2368 cb_snap_vert,
2369 &nearest2d);
2370
2371 last_index = nearest.index;
2372 }
2373
2374 if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
2375 if (sod->bvhtree[0]) {
2376 /* snap to loose edges */
2377 BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
2378 lpmat,
2379 snapdata->win_size,
2380 snapdata->mval,
2381 clip_planes_local,
2382 snapdata->clip_plane_len,
2383 &nearest,
2384 cb_snap_edge,
2385 &nearest2d);
2386 }
2387
2388 if (treedata->tree) {
2389 /* snap to looptris */
2390 BLI_bvhtree_find_nearest_projected(treedata->tree,
2391 lpmat,
2392 snapdata->win_size,
2393 snapdata->mval,
2394 clip_planes_local,
2395 snapdata->clip_plane_len,
2396 &nearest,
2397 cb_snap_tri_edges,
2398 &nearest2d);
2399 }
2400
2401 if (last_index != nearest.index) {
2402 elem = SCE_SNAP_MODE_EDGE;
2403 }
2404 }
2405 else {
2406 BLI_assert(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX);
2407 if (sod->bvhtree[0]) {
2408 /* snap to loose edge verts */
2409 BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
2410 lpmat,
2411 snapdata->win_size,
2412 snapdata->mval,
2413 clip_planes_local,
2414 snapdata->clip_plane_len,
2415 &nearest,
2416 cb_snap_edge_verts,
2417 &nearest2d);
2418 }
2419
2420 if (treedata->tree) {
2421 /* snap to looptri verts */
2422 BLI_bvhtree_find_nearest_projected(treedata->tree,
2423 lpmat,
2424 snapdata->win_size,
2425 snapdata->mval,
2426 clip_planes_local,
2427 snapdata->clip_plane_len,
2428 &nearest,
2429 cb_snap_tri_verts,
2430 &nearest2d);
2431 }
2432 }
2433
2434 if (nearest.index != -1) {
2435 *dist_px = sqrtf(nearest.dist_sq);
2436
2437 copy_v3_v3(r_loc, nearest.co);
2438 mul_m4_v3(obmat, r_loc);
2439
2440 if (r_no) {
2441 float imat[4][4];
2442 invert_m4_m4(imat, obmat);
2443
2444 copy_v3_v3(r_no, nearest.no);
2445 mul_transposed_mat3_m4_v3(imat, r_no);
2446 normalize_v3(r_no);
2447 }
2448 if (r_index) {
2449 *r_index = nearest.index;
2450 }
2451
2452 return elem;
2453 }
2454
2455 return 0;
2456 }
2457
snapEditMesh(SnapObjectContext * sctx,SnapData * snapdata,Object * ob,BMEditMesh * em,const float obmat[4][4],bool use_backface_culling,float * dist_px,float r_loc[3],float r_no[3],int * r_index)2458 static short snapEditMesh(SnapObjectContext *sctx,
2459 SnapData *snapdata,
2460 Object *ob,
2461 BMEditMesh *em,
2462 const float obmat[4][4],
2463 bool use_backface_culling,
2464 /* read/write args */
2465 float *dist_px,
2466 /* return args */
2467 float r_loc[3],
2468 float r_no[3],
2469 int *r_index)
2470 {
2471 BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE);
2472
2473 if ((snapdata->snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
2474 if (em->bm->totvert == 0) {
2475 return 0;
2476 }
2477 }
2478 else {
2479 if (em->bm->totedge == 0) {
2480 return 0;
2481 }
2482 }
2483
2484 float lpmat[4][4];
2485 mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
2486
2487 float dist_px_sq = square_f(*dist_px);
2488
2489 SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em);
2490
2491 /* Test BoundBox */
2492
2493 /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
2494 if (!snap_bound_box_check_dist(
2495 sod->min, sod->max, lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
2496 return 0;
2497 }
2498
2499 if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
2500 BVHTreeFromEditMesh treedata = {.tree = sod->bvhtree[0]};
2501
2502 if (treedata.tree == NULL) {
2503 BLI_bitmap *verts_mask = NULL;
2504 int verts_num_active = -1;
2505 if (sctx->callbacks.edit_mesh.test_vert_fn) {
2506 verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
2507 verts_num_active = BM_iter_mesh_bitmap_from_filter(
2508 BM_VERTS_OF_MESH,
2509 em->bm,
2510 verts_mask,
2511 (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
2512 sctx->callbacks.edit_mesh.user_data);
2513
2514 bvhtree_from_editmesh_verts_ex(
2515 &treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL, NULL);
2516 MEM_freeN(verts_mask);
2517 }
2518 else {
2519 BKE_bvhtree_from_editmesh_get(&treedata,
2520 em,
2521 2,
2522 BVHTREE_FROM_EM_VERTS,
2523 &sod->mesh_runtime->bvh_cache,
2524 (ThreadMutex *)sod->mesh_runtime->eval_mutex);
2525 }
2526 sod->bvhtree[0] = treedata.tree;
2527 sod->cached[0] = treedata.cached;
2528 }
2529 }
2530
2531 if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
2532 BVHTreeFromEditMesh treedata = {.tree = sod->bvhtree[1]};
2533
2534 if (treedata.tree == NULL) {
2535 BLI_bitmap *edges_mask = NULL;
2536 int edges_num_active = -1;
2537 if (sctx->callbacks.edit_mesh.test_edge_fn) {
2538 edges_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__);
2539 edges_num_active = BM_iter_mesh_bitmap_from_filter(
2540 BM_EDGES_OF_MESH,
2541 em->bm,
2542 edges_mask,
2543 (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
2544 sctx->callbacks.edit_mesh.user_data);
2545
2546 bvhtree_from_editmesh_edges_ex(
2547 &treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL, NULL);
2548 MEM_freeN(edges_mask);
2549 }
2550 else {
2551 BKE_bvhtree_from_editmesh_get(&treedata,
2552 em,
2553 2,
2554 BVHTREE_FROM_EM_EDGES,
2555 &sod->mesh_runtime->bvh_cache,
2556 sod->mesh_runtime->eval_mutex);
2557 }
2558 sod->bvhtree[1] = treedata.tree;
2559 sod->cached[1] = treedata.cached;
2560 }
2561 }
2562
2563 Nearest2dUserData nearest2d = {
2564 .userdata = em,
2565 .get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get,
2566 .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get,
2567 .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy,
2568 .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
2569 .use_backface_culling = use_backface_culling,
2570 };
2571
2572 BVHTreeNearest nearest = {
2573 .index = -1,
2574 .dist_sq = dist_px_sq,
2575 };
2576 short elem = SCE_SNAP_MODE_VERTEX;
2577
2578 float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
2579 transpose_m4_m4(tobmat, obmat);
2580
2581 for (int i = snapdata->clip_plane_len; i--;) {
2582 mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
2583 }
2584
2585 if (sod->bvhtree[0] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
2586 BM_mesh_elem_table_ensure(em->bm, BM_VERT);
2587 BM_mesh_elem_index_ensure(em->bm, BM_VERT);
2588 BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
2589 lpmat,
2590 snapdata->win_size,
2591 snapdata->mval,
2592 clip_planes_local,
2593 snapdata->clip_plane_len,
2594 &nearest,
2595 cb_snap_vert,
2596 &nearest2d);
2597 }
2598
2599 if (sod->bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE)) {
2600 int last_index = nearest.index;
2601 nearest.index = -1;
2602 BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
2603 BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT);
2604 BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
2605 lpmat,
2606 snapdata->win_size,
2607 snapdata->mval,
2608 clip_planes_local,
2609 snapdata->clip_plane_len,
2610 &nearest,
2611 cb_snap_edge,
2612 &nearest2d);
2613
2614 if (nearest.index != -1) {
2615 elem = SCE_SNAP_MODE_EDGE;
2616 }
2617 else {
2618 nearest.index = last_index;
2619 }
2620 }
2621
2622 if (nearest.index != -1) {
2623 *dist_px = sqrtf(nearest.dist_sq);
2624
2625 copy_v3_v3(r_loc, nearest.co);
2626 mul_m4_v3(obmat, r_loc);
2627 if (r_no) {
2628 float imat[4][4];
2629 invert_m4_m4(imat, obmat);
2630
2631 copy_v3_v3(r_no, nearest.no);
2632 mul_transposed_mat3_m4_v3(imat, r_no);
2633 normalize_v3(r_no);
2634 }
2635 if (r_index) {
2636 *r_index = nearest.index;
2637 }
2638
2639 return elem;
2640 }
2641
2642 return 0;
2643 }
2644
2645 struct SnapObjUserData {
2646 SnapData *snapdata;
2647 /* read/write args */
2648 float *dist_px;
2649 /* return args */
2650 float *r_loc;
2651 float *r_no;
2652 int *r_index;
2653 Object **r_ob;
2654 float (*r_obmat)[4];
2655 short ret;
2656 };
2657
2658 /**
2659 * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
2660 *
2661 * \note Duplicate args here are documented at #snapObjectsRay
2662 */
snap_obj_fn(SnapObjectContext * sctx,Object * ob,float obmat[4][4],bool use_obedit,bool use_backface_culling,bool UNUSED (is_object_active),void * data)2663 static void snap_obj_fn(SnapObjectContext *sctx,
2664 Object *ob,
2665 float obmat[4][4],
2666 bool use_obedit,
2667 bool use_backface_culling,
2668 bool UNUSED(is_object_active),
2669 void *data)
2670 {
2671 struct SnapObjUserData *dt = data;
2672 short retval = 0;
2673
2674 switch (ob->type) {
2675 case OB_MESH: {
2676 Mesh *me = ob->data;
2677 if (BKE_object_is_in_editmode(ob)) {
2678 if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
2679 /* Operators only update the editmesh looptris of the original mesh. */
2680 BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
2681 retval = snapEditMesh(sctx,
2682 dt->snapdata,
2683 ob,
2684 em_orig,
2685 obmat,
2686 use_backface_culling,
2687 dt->dist_px,
2688 dt->r_loc,
2689 dt->r_no,
2690 dt->r_index);
2691 break;
2692 }
2693
2694 BMEditMesh *em = BKE_editmesh_from_object(ob);
2695 if (em->mesh_eval_final) {
2696 me = em->mesh_eval_final;
2697 }
2698 }
2699 else if (ob->dt == OB_BOUNDBOX) {
2700 /* Do not snap to objects that are in bounding box display mode */
2701 return;
2702 }
2703
2704 retval = snapMesh(sctx,
2705 dt->snapdata,
2706 ob,
2707 me,
2708 obmat,
2709 use_backface_culling,
2710 dt->dist_px,
2711 dt->r_loc,
2712 dt->r_no,
2713 dt->r_index);
2714 break;
2715 }
2716 case OB_ARMATURE:
2717 retval = snapArmature(
2718 dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
2719 break;
2720 case OB_CURVE:
2721 retval = snapCurve(
2722 dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
2723 break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
2724 case OB_SURF:
2725 case OB_FONT: {
2726 Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
2727 if (mesh_eval) {
2728 retval |= snapMesh(sctx,
2729 dt->snapdata,
2730 ob,
2731 mesh_eval,
2732 obmat,
2733 use_backface_culling,
2734 dt->dist_px,
2735 dt->r_loc,
2736 dt->r_no,
2737 dt->r_index);
2738 }
2739 break;
2740 }
2741 case OB_EMPTY:
2742 case OB_GPENCIL:
2743 case OB_LAMP:
2744 retval = snap_object_center(
2745 dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
2746 break;
2747 case OB_CAMERA:
2748 retval = snapCamera(
2749 sctx, dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
2750 break;
2751 }
2752
2753 if (retval) {
2754 if (dt->r_ob) {
2755 *dt->r_ob = ob;
2756 }
2757 if (dt->r_obmat) {
2758 copy_m4_m4(dt->r_obmat, obmat);
2759 }
2760 dt->ret = retval;
2761 }
2762 }
2763
2764 /**
2765 * Main Snapping Function
2766 * ======================
2767 *
2768 * Walks through all objects in the scene to find the closest snap element ray.
2769 *
2770 * \param sctx: Snap context to store data.
2771 * \param snapdata: struct generated in `get_snapdata`.
2772 * \param params: Parameters for control snap behavior.
2773 *
2774 * Read/Write Args
2775 * ---------------
2776 *
2777 * \param dist_px: Maximum threshold distance (in pixels).
2778 *
2779 * Output Args
2780 * -----------
2781 *
2782 * \param r_loc: Hit location.
2783 * \param r_no: Hit normal (optional).
2784 * \param r_index: Hit index or -1 when no valid index is found.
2785 * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``).
2786 * \param r_ob: Hit object.
2787 * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
2788 */
snapObjectsRay(SnapObjectContext * sctx,Depsgraph * depsgraph,SnapData * snapdata,const struct SnapObjectParams * params,float * dist_px,float r_loc[3],float r_no[3],int * r_index,Object ** r_ob,float r_obmat[4][4])2789 static short snapObjectsRay(SnapObjectContext *sctx,
2790 Depsgraph *depsgraph,
2791 SnapData *snapdata,
2792 const struct SnapObjectParams *params,
2793 /* read/write args */
2794 /* Parameters below cannot be const, because they are assigned to a
2795 * non-const variable (readability-non-const-parameter). */
2796 float *dist_px /* NOLINT */,
2797 /* return args */
2798 float r_loc[3] /* NOLINT */,
2799 float r_no[3] /* NOLINT */,
2800 int *r_index /* NOLINT */,
2801 Object **r_ob,
2802 float r_obmat[4][4])
2803 {
2804 struct SnapObjUserData data = {
2805 .snapdata = snapdata,
2806 .dist_px = dist_px,
2807 .r_loc = r_loc,
2808 .r_no = r_no,
2809 .r_ob = r_ob,
2810 .r_index = r_index,
2811 .r_obmat = r_obmat,
2812 .ret = 0,
2813 };
2814
2815 iter_snap_objects(sctx, depsgraph, params, snap_obj_fn, &data);
2816
2817 return data.ret;
2818 }
2819
2820 /** \} */
2821
2822 /* -------------------------------------------------------------------- */
2823 /** \name Public Object Snapping API
2824 * \{ */
2825
ED_transform_snap_object_context_create(Scene * scene,int flag)2826 SnapObjectContext *ED_transform_snap_object_context_create(Scene *scene, int flag)
2827 {
2828 SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
2829
2830 sctx->flag = flag;
2831
2832 sctx->scene = scene;
2833
2834 sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
2835 /* Initialize as needed (edit-mode only). */
2836 sctx->cache.data_to_object_map = NULL;
2837 sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
2838
2839 return sctx;
2840 }
2841
ED_transform_snap_object_context_create_view3d(Scene * scene,int flag,const ARegion * region,const View3D * v3d)2842 SnapObjectContext *ED_transform_snap_object_context_create_view3d(Scene *scene,
2843 int flag,
2844 /* extra args for view3d */
2845 const ARegion *region,
2846 const View3D *v3d)
2847 {
2848 SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, flag);
2849
2850 sctx->use_v3d = true;
2851 sctx->v3d_data.region = region;
2852 sctx->v3d_data.v3d = v3d;
2853
2854 return sctx;
2855 }
2856
snap_object_data_free(void * sod_v)2857 static void snap_object_data_free(void *sod_v)
2858 {
2859 SnapObjectData *sod = sod_v;
2860 snap_object_data_clear(sod);
2861 }
2862
ED_transform_snap_object_context_destroy(SnapObjectContext * sctx)2863 void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
2864 {
2865 BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
2866 if (sctx->cache.data_to_object_map != NULL) {
2867 BLI_ghash_free(sctx->cache.data_to_object_map, NULL, NULL);
2868 }
2869 BLI_memarena_free(sctx->cache.mem_arena);
2870
2871 MEM_freeN(sctx);
2872 }
2873
ED_transform_snap_object_context_set_editmesh_callbacks(SnapObjectContext * sctx,bool (* test_vert_fn)(BMVert *,void * user_data),bool (* test_edge_fn)(BMEdge *,void * user_data),bool (* test_face_fn)(BMFace *,void * user_data),void * user_data)2874 void ED_transform_snap_object_context_set_editmesh_callbacks(
2875 SnapObjectContext *sctx,
2876 bool (*test_vert_fn)(BMVert *, void *user_data),
2877 bool (*test_edge_fn)(BMEdge *, void *user_data),
2878 bool (*test_face_fn)(BMFace *, void *user_data),
2879 void *user_data)
2880 {
2881 sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn;
2882 sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn;
2883 sctx->callbacks.edit_mesh.test_face_fn = test_face_fn;
2884
2885 sctx->callbacks.edit_mesh.user_data = user_data;
2886 }
2887
ED_transform_snap_object_project_ray_ex(SnapObjectContext * sctx,Depsgraph * depsgraph,const struct SnapObjectParams * params,const float ray_start[3],const float ray_normal[3],float * ray_depth,float r_loc[3],float r_no[3],int * r_index,Object ** r_ob,float r_obmat[4][4])2888 bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,
2889 Depsgraph *depsgraph,
2890 const struct SnapObjectParams *params,
2891 const float ray_start[3],
2892 const float ray_normal[3],
2893 float *ray_depth,
2894 float r_loc[3],
2895 float r_no[3],
2896 int *r_index,
2897 Object **r_ob,
2898 float r_obmat[4][4])
2899 {
2900 return raycastObjects(sctx,
2901 depsgraph,
2902 params,
2903 ray_start,
2904 ray_normal,
2905 ray_depth,
2906 r_loc,
2907 r_no,
2908 r_index,
2909 r_ob,
2910 r_obmat,
2911 NULL);
2912 }
2913
2914 /**
2915 * Fill in a list of all hits.
2916 *
2917 * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
2918 * \param sort: Optionally sort the hits by depth.
2919 * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
2920 */
ED_transform_snap_object_project_ray_all(SnapObjectContext * sctx,Depsgraph * depsgraph,const struct SnapObjectParams * params,const float ray_start[3],const float ray_normal[3],float ray_depth,bool sort,ListBase * r_hit_list)2921 bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
2922 Depsgraph *depsgraph,
2923 const struct SnapObjectParams *params,
2924 const float ray_start[3],
2925 const float ray_normal[3],
2926 float ray_depth,
2927 bool sort,
2928 ListBase *r_hit_list)
2929 {
2930 if (ray_depth == -1.0f) {
2931 ray_depth = BVH_RAYCAST_DIST_MAX;
2932 }
2933
2934 #ifdef DEBUG
2935 float ray_depth_prev = ray_depth;
2936 #endif
2937
2938 bool retval = raycastObjects(sctx,
2939 depsgraph,
2940 params,
2941 ray_start,
2942 ray_normal,
2943 &ray_depth,
2944 NULL,
2945 NULL,
2946 NULL,
2947 NULL,
2948 NULL,
2949 r_hit_list);
2950
2951 /* meant to be readonly for 'all' hits, ensure it is */
2952 #ifdef DEBUG
2953 BLI_assert(ray_depth_prev == ray_depth);
2954 #endif
2955
2956 if (sort) {
2957 BLI_listbase_sort(r_hit_list, hit_depth_cmp);
2958 }
2959
2960 return retval;
2961 }
2962
2963 /**
2964 * Convenience function for snap ray-casting.
2965 *
2966 * Given a ray, cast it into the scene (snapping to faces).
2967 *
2968 * \return Snap success
2969 */
transform_snap_context_project_ray_impl(SnapObjectContext * sctx,Depsgraph * depsgraph,const struct SnapObjectParams * params,const float ray_start[3],const float ray_normal[3],float * ray_depth,float r_co[3],float r_no[3])2970 static bool transform_snap_context_project_ray_impl(SnapObjectContext *sctx,
2971 Depsgraph *depsgraph,
2972 const struct SnapObjectParams *params,
2973 const float ray_start[3],
2974 const float ray_normal[3],
2975 float *ray_depth,
2976 float r_co[3],
2977 float r_no[3])
2978 {
2979 bool ret;
2980
2981 /* try snap edge, then face if it fails */
2982 ret = ED_transform_snap_object_project_ray_ex(
2983 sctx, depsgraph, params, ray_start, ray_normal, ray_depth, r_co, r_no, NULL, NULL, NULL);
2984
2985 return ret;
2986 }
2987
ED_transform_snap_object_project_ray(SnapObjectContext * sctx,Depsgraph * depsgraph,const struct SnapObjectParams * params,const float ray_origin[3],const float ray_direction[3],float * ray_depth,float r_co[3],float r_no[3])2988 bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
2989 Depsgraph *depsgraph,
2990 const struct SnapObjectParams *params,
2991 const float ray_origin[3],
2992 const float ray_direction[3],
2993 float *ray_depth,
2994 float r_co[3],
2995 float r_no[3])
2996 {
2997 float ray_depth_fallback;
2998 if (ray_depth == NULL) {
2999 ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
3000 ray_depth = &ray_depth_fallback;
3001 }
3002
3003 return transform_snap_context_project_ray_impl(
3004 sctx, depsgraph, params, ray_origin, ray_direction, ray_depth, r_co, r_no);
3005 }
3006
transform_snap_context_project_view3d_mixed_impl(SnapObjectContext * sctx,Depsgraph * depsgraph,const ushort snap_to_flag,const struct SnapObjectParams * params,const float mval[2],const float prev_co[3],float * dist_px,float r_loc[3],float r_no[3],int * r_index,Object ** r_ob,float r_obmat[4][4])3007 static short transform_snap_context_project_view3d_mixed_impl(
3008 SnapObjectContext *sctx,
3009 Depsgraph *depsgraph,
3010 const ushort snap_to_flag,
3011 const struct SnapObjectParams *params,
3012 const float mval[2],
3013 const float prev_co[3],
3014 float *dist_px,
3015 float r_loc[3],
3016 float r_no[3],
3017 int *r_index,
3018 Object **r_ob,
3019 float r_obmat[4][4])
3020 {
3021 BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
3022 SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) !=
3023 0);
3024
3025 short retval = 0;
3026
3027 bool has_hit = false;
3028 Object *ob = NULL;
3029 float loc[3], no[3], obmat[4][4];
3030 int index = -1;
3031
3032 const ARegion *region = sctx->v3d_data.region;
3033 const RegionView3D *rv3d = region->regiondata;
3034
3035 bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(sctx->v3d_data.v3d);
3036
3037 if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) {
3038 float ray_start[3], ray_normal[3];
3039 if (!ED_view3d_win_to_ray_clipped_ex(depsgraph,
3040 sctx->v3d_data.region,
3041 sctx->v3d_data.v3d,
3042 mval,
3043 NULL,
3044 ray_normal,
3045 ray_start,
3046 true)) {
3047 return 0;
3048 }
3049
3050 float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
3051
3052 has_hit = raycastObjects(sctx,
3053 depsgraph,
3054 params,
3055 ray_start,
3056 ray_normal,
3057 &dummy_ray_depth,
3058 loc,
3059 no,
3060 &index,
3061 &ob,
3062 obmat,
3063 NULL);
3064
3065 if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) {
3066 retval = SCE_SNAP_MODE_FACE;
3067
3068 copy_v3_v3(r_loc, loc);
3069 if (r_no) {
3070 copy_v3_v3(r_no, no);
3071 }
3072 if (r_ob) {
3073 *r_ob = ob;
3074 }
3075 if (r_obmat) {
3076 copy_m4_m4(r_obmat, obmat);
3077 }
3078 if (r_index) {
3079 *r_index = index;
3080 }
3081 }
3082 }
3083
3084 if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
3085 SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
3086 short elem_test, elem = 0;
3087 float dist_px_tmp = *dist_px;
3088
3089 SnapData snapdata;
3090 copy_m4_m4(snapdata.pmat, rv3d->persmat);
3091 snapdata.win_size[0] = region->winx;
3092 snapdata.win_size[1] = region->winy;
3093 copy_v2_v2(snapdata.mval, mval);
3094 snapdata.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
3095
3096 /* First snap to edge instead of middle or perpendicular. */
3097 snapdata.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE);
3098 if (snap_to_flag & (SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
3099 snapdata.snap_to_flag |= SCE_SNAP_MODE_EDGE;
3100 }
3101
3102 planes_from_projmat(
3103 snapdata.pmat, NULL, NULL, NULL, NULL, snapdata.clip_plane[0], snapdata.clip_plane[1]);
3104
3105 snapdata.clip_plane_len = 2;
3106 snapdata.has_occlusion_plane = false;
3107
3108 /* By convention we only snap to the original elements of a curve. */
3109 if (has_hit && ob->type != OB_CURVE) {
3110 /* Compute the new clip_pane but do not add it yet. */
3111 float new_clipplane[4];
3112 plane_from_point_normal_v3(new_clipplane, loc, no);
3113 if (dot_v3v3(snapdata.clip_plane[0], new_clipplane) > 0.0f) {
3114 /* The plane is facing the wrong direction. */
3115 negate_v4(new_clipplane);
3116 }
3117
3118 /* Small offset to simulate a kind of volume for edges and vertices. */
3119 new_clipplane[3] += 0.01f;
3120
3121 /* Try to snap only to the polygon. */
3122 elem_test = snap_mesh_polygon(
3123 sctx, &snapdata, ob, obmat, params->use_backface_culling, &dist_px_tmp, loc, no, &index);
3124 if (elem_test) {
3125 elem = elem_test;
3126 }
3127
3128 /* Add the new clip plane to the beginning of the list. */
3129 for (int i = snapdata.clip_plane_len; i != 0; i--) {
3130 copy_v4_v4(snapdata.clip_plane[i], snapdata.clip_plane[i - 1]);
3131 }
3132 copy_v4_v4(snapdata.clip_plane[0], new_clipplane);
3133 snapdata.clip_plane_len++;
3134 snapdata.has_occlusion_plane = true;
3135 }
3136
3137 elem_test = snapObjectsRay(
3138 sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat);
3139 if (elem_test) {
3140 elem = elem_test;
3141 }
3142
3143 if ((elem == SCE_SNAP_MODE_EDGE) &&
3144 (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT |
3145 SCE_SNAP_MODE_EDGE_PERPENDICULAR))) {
3146 snapdata.snap_to_flag = snap_to_flag;
3147 elem = snap_mesh_edge_verts_mixed(sctx,
3148 &snapdata,
3149 ob,
3150 obmat,
3151 *dist_px,
3152 prev_co,
3153 params->use_backface_culling,
3154 &dist_px_tmp,
3155 loc,
3156 no,
3157 &index);
3158 }
3159
3160 if (elem & snap_to_flag) {
3161 retval = elem;
3162
3163 copy_v3_v3(r_loc, loc);
3164 if (r_no) {
3165 copy_v3_v3(r_no, no);
3166 }
3167 if (r_ob) {
3168 *r_ob = ob;
3169 }
3170 if (r_obmat) {
3171 copy_m4_m4(r_obmat, obmat);
3172 }
3173 if (r_index) {
3174 *r_index = index;
3175 }
3176
3177 *dist_px = dist_px_tmp;
3178 }
3179 }
3180
3181 return retval;
3182 }
3183
ED_transform_snap_object_project_view3d_ex(SnapObjectContext * sctx,Depsgraph * depsgraph,const ushort snap_to,const struct SnapObjectParams * params,const float mval[2],const float prev_co[3],float * dist_px,float r_loc[3],float r_no[3],int * r_index,Object ** r_ob,float r_obmat[4][4])3184 short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
3185 Depsgraph *depsgraph,
3186 const ushort snap_to,
3187 const struct SnapObjectParams *params,
3188 const float mval[2],
3189 const float prev_co[3],
3190 float *dist_px,
3191 float r_loc[3],
3192 float r_no[3],
3193 int *r_index,
3194 Object **r_ob,
3195 float r_obmat[4][4])
3196 {
3197 return transform_snap_context_project_view3d_mixed_impl(sctx,
3198 depsgraph,
3199 snap_to,
3200 params,
3201 mval,
3202 prev_co,
3203 dist_px,
3204 r_loc,
3205 r_no,
3206 r_index,
3207 r_ob,
3208 r_obmat);
3209 }
3210
3211 /**
3212 * Convenience function for performing snapping.
3213 *
3214 * Given a 2D region value, snap to vert/edge/face.
3215 *
3216 * \param sctx: Snap context.
3217 * \param mval: Screenspace coordinate.
3218 * \param prev_co: Coordinate for perpendicular point calculation (optional).
3219 * \param dist_px: Maximum distance to snap (in pixels).
3220 * \param r_loc: hit location.
3221 * \param r_no: hit normal (optional).
3222 * \return Snap success
3223 */
ED_transform_snap_object_project_view3d(SnapObjectContext * sctx,Depsgraph * depsgraph,const ushort snap_to,const struct SnapObjectParams * params,const float mval[2],const float prev_co[3],float * dist_px,float r_loc[3],float r_no[3])3224 bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
3225 Depsgraph *depsgraph,
3226 const ushort snap_to,
3227 const struct SnapObjectParams *params,
3228 const float mval[2],
3229 const float prev_co[3],
3230 float *dist_px,
3231 float r_loc[3],
3232 float r_no[3])
3233 {
3234 return ED_transform_snap_object_project_view3d_ex(sctx,
3235 depsgraph,
3236 snap_to,
3237 params,
3238 mval,
3239 prev_co,
3240 dist_px,
3241 r_loc,
3242 r_no,
3243 NULL,
3244 NULL,
3245 NULL) != 0;
3246 }
3247
3248 /**
3249 * see: #ED_transform_snap_object_project_ray_all
3250 */
ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext * sctx,Depsgraph * depsgraph,const struct SnapObjectParams * params,const float mval[2],float ray_depth,bool sort,ListBase * r_hit_list)3251 bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
3252 Depsgraph *depsgraph,
3253 const struct SnapObjectParams *params,
3254 const float mval[2],
3255 float ray_depth,
3256 bool sort,
3257 ListBase *r_hit_list)
3258 {
3259 float ray_start[3], ray_normal[3];
3260
3261 if (!ED_view3d_win_to_ray_clipped_ex(depsgraph,
3262 sctx->v3d_data.region,
3263 sctx->v3d_data.v3d,
3264 mval,
3265 NULL,
3266 ray_normal,
3267 ray_start,
3268 true)) {
3269 return false;
3270 }
3271
3272 return ED_transform_snap_object_project_ray_all(
3273 sctx, depsgraph, params, ray_start, ray_normal, ray_depth, sort, r_hit_list);
3274 }
3275
3276 /** \} */
3277