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