Blender  V2.93
transform_snap.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <float.h>
25 
26 #include "PIL_time.h"
27 
29 
30 #include "BLI_blenlib.h"
31 #include "BLI_math.h"
32 
33 #include "GPU_immediate.h"
34 #include "GPU_state.h"
35 
36 #include "BKE_context.h"
37 #include "BKE_editmesh.h"
38 #include "BKE_layer.h"
39 #include "BKE_object.h"
40 #include "BKE_scene.h"
41 
42 #include "RNA_access.h"
43 
44 #include "SEQ_sequencer.h"
45 #include "SEQ_time.h"
46 
47 #include "WM_types.h"
48 
49 #include "ED_gizmo_library.h"
50 #include "ED_markers.h"
51 #include "ED_node.h"
53 #include "ED_uvedit.h"
54 
55 #include "UI_resources.h"
56 #include "UI_view2d.h"
57 
58 #include "MEM_guardedalloc.h"
59 
60 #include "transform.h"
61 #include "transform_convert.h"
62 #include "transform_snap.h"
63 
64 /* this should be passed as an arg for use in snap functions */
65 #undef BASACT
66 
67 /* use half of flt-max so we can scale up without an exception */
68 
69 /* -------------------------------------------------------------------- */
73 static void setSnappingCallback(TransInfo *t);
74 
75 /* static void CalcSnapGrid(TransInfo *t, float *vec); */
76 static void CalcSnapGeometry(TransInfo *t, float *vec);
77 
78 static void TargetSnapMedian(TransInfo *t);
79 static void TargetSnapCenter(TransInfo *t);
80 static void TargetSnapClosest(TransInfo *t);
81 static void TargetSnapActive(TransInfo *t);
82 
85 /* -------------------------------------------------------------------- */
89 static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select);
90 static NodeBorder snapNodeBorder(int snap_node_mode);
91 
92 #if 0
93 int BIF_snappingSupported(Object *obedit)
94 {
95  int status = 0;
96 
97  /* only support object mesh, armature, curves */
98  if (obedit == NULL || ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) {
99  status = 1;
100  }
101 
102  return status;
103 }
104 #endif
105 
107 {
108  BLI_assert(t->spacetype == SPACE_VIEW3D);
109  View3D *v3d = t->view;
110  if ((v3d->shading.type == OB_SOLID) && (v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING)) {
111  return true;
112  }
113  if (v3d->shading.type == OB_RENDER &&
114  (t->scene->display.shading.flag & V3D_SHADING_BACKFACE_CULLING) &&
116  return true;
117  }
118  if (t->settings->snap_flag & SCE_SNAP_BACKFACE_CULLING) {
119  return true;
120  }
121  return false;
122 }
123 
124 bool validSnap(const TransInfo *t)
125 {
126  return (t->tsnap.status & (POINT_INIT | TARGET_INIT)) == (POINT_INIT | TARGET_INIT) ||
127  (t->tsnap.status & (MULTI_POINTS | TARGET_INIT)) == (MULTI_POINTS | TARGET_INIT);
128 }
129 
130 bool activeSnap(const TransInfo *t)
131 {
132  return ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP) ||
133  ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT);
134 }
135 
137 {
138  ToolSettings *ts = t->settings;
139  if (t->mode == TFM_TRANSLATION) {
141  }
142  if (t->mode == TFM_ROTATION) {
144  }
145  if (t->mode == TFM_RESIZE) {
147  }
148  if (t->mode == TFM_VERT_SLIDE) {
149  return true;
150  }
151  if (t->mode == TFM_EDGE_SLIDE) {
152  return true;
153  }
154 
155  return false;
156 }
157 
158 static bool doForceIncrementSnap(const TransInfo *t)
159 {
160  return !transformModeUseSnap(t);
161 }
162 
163 void drawSnapping(const struct bContext *C, TransInfo *t)
164 {
165  uchar col[4], selectedCol[4], activeCol[4];
166 
167  if (!activeSnap(t)) {
168  return;
169  }
170 
172  col[3] = 128;
173 
174  UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
175  selectedCol[3] = 128;
176 
177  UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
178  activeCol[3] = 192;
179 
180  if (t->spacetype == SPACE_VIEW3D) {
181  bool draw_target = (t->tsnap.status & TARGET_INIT) &&
182  (t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
183 
184  if (draw_target || validSnap(t)) {
185  const float *loc_cur = NULL;
186  const float *loc_prev = NULL;
187  const float *normal = NULL;
188 
190 
192  if (!BLI_listbase_is_empty(&t->tsnap.points)) {
193  /* Draw snap points. */
194 
195  float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE);
196  float view_inv[4][4];
197  copy_m4_m4(view_inv, rv3d->viewinv);
198 
201 
203 
204  LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) {
205  if (p == t->tsnap.selectedPoint) {
206  immUniformColor4ubv(selectedCol);
207  }
208  else {
210  }
211  imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos);
212  }
213 
215  }
216 
217  /* draw normal if needed */
219  normal = t->tsnap.snapNormal;
220  }
221 
222  if (draw_target) {
223  loc_prev = t->tsnap.snapTarget;
224  }
225 
226  if (validSnap(t)) {
227  loc_cur = t->tsnap.snapPoint;
228  }
229 
231  rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem);
232 
234  }
235  }
236  else if (t->spacetype == SPACE_IMAGE) {
237  if (validSnap(t)) {
238  /* This will not draw, and I'm nor sure why - campbell */
239  /* TODO: see 2.7x for non-working code */
240  }
241  }
242  else if (t->spacetype == SPACE_NODE) {
243  if (validSnap(t)) {
244  ARegion *region = CTX_wm_region(C);
245  TransSnapPoint *p;
246  float size;
247 
249 
251 
254 
256 
257  for (p = t->tsnap.points.first; p; p = p->next) {
258  if (p == t->tsnap.selectedPoint) {
259  immUniformColor4ubv(selectedCol);
260  }
261  else {
263  }
264 
265  ED_node_draw_snap(&region->v2d, p->co, size, 0, pos);
266  }
267 
268  if (t->tsnap.status & POINT_INIT) {
269  immUniformColor4ubv(activeCol);
270 
271  ED_node_draw_snap(&region->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos);
272  }
273 
275 
277  }
278  }
279 }
280 
282 {
283  eRedrawFlag status = TREDRAW_NOTHING;
284 
285 #if 0 /* XXX need a proper selector for all snap mode */
286  if (BIF_snappingSupported(t->obedit) && event->type == TABKEY && event->shift) {
287  /* toggle snap and reinit */
288  t->settings->snap_flag ^= SCE_SNAP;
289  initSnapping(t, NULL);
290  status = TREDRAW_HARD;
291  }
292 #endif
293  if (event->type == MOUSEMOVE) {
294  status |= updateSelectedSnapPoint(t);
295  }
296 
297  return status;
298 }
299 
301 {
302  if (!t->tsnap.project) {
303  return;
304  }
305 
306  if (!activeSnap(t) || (t->flag & T_NO_PROJECT)) {
307  return;
308  }
309 
310  if (doForceIncrementSnap(t)) {
311  return;
312  }
313 
314  float tvec[3];
315  int i;
316 
317  /* XXX FLICKER IN OBJECT MODE */
319  TransData *td = tc->data;
320  for (i = 0; i < tc->data_len; i++, td++) {
321  float iloc[3], loc[3], no[3];
322  float mval_fl[2];
323  if (td->flag & TD_SKIP) {
324  continue;
325  }
326 
327  if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
328  continue;
329  }
330 
331  copy_v3_v3(iloc, td->loc);
332  if (tc->use_local_mat) {
333  mul_m4_v3(tc->mat, iloc);
334  }
335  else if (t->options & CTX_OBJECT) {
336  BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
337  copy_v3_v3(iloc, td->ob->obmat[3]);
338  }
339 
340  if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) ==
341  V3D_PROJ_RET_OK) {
343  t->tsnap.object_context,
344  t->depsgraph,
346  &(const struct SnapObjectParams){
347  .snap_select = t->tsnap.modeSelect,
348  .use_object_edit_cage = (t->flag & T_EDIT) != 0,
349  .use_occlusion_test = false,
350  .use_backface_culling = t->tsnap.use_backface_culling,
351  },
352  mval_fl,
353  NULL,
354  0,
355  loc,
356  no)) {
357 #if 0
358  if (tc->use_local_mat) {
359  mul_m4_v3(tc->imat, loc);
360  }
361 #endif
362 
363  sub_v3_v3v3(tvec, loc, iloc);
364 
365  mul_m3_v3(td->smtx, tvec);
366 
367  add_v3_v3(td->loc, tvec);
368 
369  if (t->tsnap.align && (t->options & CTX_OBJECT)) {
370  /* handle alignment as well */
371  const float *original_normal;
372  float mat[3][3];
373 
374  /* In pose mode, we want to align normals with Y axis of bones... */
375  original_normal = td->axismtx[2];
376 
377  rotation_between_vecs_to_mat3(mat, original_normal, no);
378 
379  transform_data_ext_rotate(td, mat, true);
380 
381  /* TODO support constraints for rotation too? see ElementRotation */
382  }
383  }
384  }
385 
386 #if 0 /* TODO: support this? */
387  constraintTransLim(t, td);
388 #endif
389  }
390  }
391 }
392 
394 {
395  int i;
396 
397  if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
398  return;
399  }
400 
401  float grid_size = (t->modifiers & MOD_PRECISION) ? t->snap_spatial[1] : t->snap_spatial[0];
402 
403  /* early exit on unusable grid size */
404  if (grid_size == 0.0f) {
405  return;
406  }
407 
409  TransData *td;
410 
411  for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
412  float iloc[3], loc[3], tvec[3];
413  if (td->flag & TD_SKIP) {
414  continue;
415  }
416 
417  if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
418  continue;
419  }
420 
421  copy_v3_v3(iloc, td->loc);
422  if (tc->use_local_mat) {
423  mul_m4_v3(tc->mat, iloc);
424  }
425  else if (t->options & CTX_OBJECT) {
426  BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
427  copy_v3_v3(iloc, td->ob->obmat[3]);
428  }
429 
430  mul_v3_v3fl(loc, iloc, 1.0f / grid_size);
431  loc[0] = roundf(loc[0]);
432  loc[1] = roundf(loc[1]);
433  loc[2] = roundf(loc[2]);
434  mul_v3_fl(loc, grid_size);
435 
436  sub_v3_v3v3(tvec, loc, iloc);
437  mul_m3_v3(td->smtx, tvec);
438  add_v3_v3(td->loc, tvec);
439  }
440  }
441 }
442 
443 void applySnapping(TransInfo *t, float *vec)
444 {
445  /* Each Trans Data already makes the snap to face */
446  if (doForceIncrementSnap(t)) {
447  return;
448  }
449 
450  if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) {
451  /* The snap has already been resolved for each transdata. */
452  return;
453  }
454 
455  if (t->tsnap.status & SNAP_FORCED) {
456  t->tsnap.targetSnap(t);
457 
458  t->tsnap.applySnap(t, vec);
459  }
460  else if (((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) != 0) &&
461  activeSnap(t)) {
462  double current = PIL_check_seconds_timer();
463 
464  /* Time base quirky code to go around find-nearest slowness. */
465  /* TODO: add exception for object mode, no need to slow it down then. */
466  if (current - t->tsnap.last >= 0.01) {
467  t->tsnap.calcSnap(t, vec);
468  t->tsnap.targetSnap(t);
469 
470  t->tsnap.last = current;
471  }
472  if (validSnap(t)) {
473  t->tsnap.applySnap(t, vec);
474  }
475  }
476 }
477 
479 {
480  t->tsnap.status = 0;
481  t->tsnap.snapElem = 0;
482  t->tsnap.align = false;
483  t->tsnap.project = 0;
484  t->tsnap.mode = 0;
485  t->tsnap.modeSelect = 0;
486  t->tsnap.target = 0;
487  t->tsnap.last = 0;
488 
489  t->tsnap.snapNormal[0] = 0;
490  t->tsnap.snapNormal[1] = 0;
491  t->tsnap.snapNormal[2] = 0;
492 
493  t->tsnap.snapNodeBorder = 0;
494 }
495 
497 {
498  return t->tsnap.align;
499 }
500 
502 {
503  if (validSnap(t)) {
504  if (!is_zero_v3(t->tsnap.snapNormal)) {
505  return true;
506  }
507  }
508 
509  return false;
510 }
511 
513 {
516  return false;
517  }
518 
519  return true;
520 }
521 
523 {
525  return false;
526  }
527 
528  BMLoop *l_iter, *l_first;
529  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
530  do {
531  if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
532  return false;
533  }
534  } while ((l_iter = l_iter->next) != l_first);
535 
536  return true;
537 }
538 
540 {
541  ToolSettings *ts = t->settings;
542  /* All obedit types will match. */
543  const int obedit_type = t->obedit_type;
544  ViewLayer *view_layer = t->view_layer;
545  Base *base_act = view_layer->basact;
546 
547  if (t->spacetype == SPACE_NODE) {
548  /* force project off when not supported */
549  t->tsnap.project = 0;
550 
551  t->tsnap.mode = ts->snap_node_mode;
552  }
553  else if (t->spacetype == SPACE_IMAGE) {
554  /* force project off when not supported */
555  t->tsnap.project = 0;
556 
557  t->tsnap.mode = ts->snap_uv_mode;
558  }
559  else {
560  /* force project off when not supported */
561  if ((ts->snap_mode & SCE_SNAP_MODE_FACE) == 0) {
562  t->tsnap.project = 0;
563  }
564 
565  t->tsnap.mode = ts->snap_mode;
566  if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) &&
567  (t->mode == TFM_TRANSLATION)) {
568  /* Special case in which snap to increments is transformed to snap to grid. */
569  t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT;
570  t->tsnap.mode |= SCE_SNAP_MODE_GRID;
571  }
572  }
573 
574  if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) {
575  /* Only 3D view or UV. */
576  /* Not with camera selected in camera view. */
577 
579 
581  /* In "Edit Strokes" mode,
582  * snap tool can perform snap to selected or active objects (see T49632)
583  * TODO: perform self snap in gpencil_strokes.
584  *
585  * When we're moving the origins, allow snapping onto our own geometry (see T69132). */
586  t->tsnap.modeSelect = SNAP_ALL;
587  }
588  else if ((obedit_type != -1) &&
589  ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) {
590  /* Edit mode */
591  /* Temporary limited to edit mode meshes, armature, curves, metaballs. */
592 
593  if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
594  /* Exclude editmesh if using proportional edit */
595  t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
596  }
597  else {
598  t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE;
599  }
600  }
601  else if ((obedit_type == -1) && base_act && base_act->object &&
602  (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
603  /* Particles edit mode. */
604  t->tsnap.modeSelect = SNAP_ALL;
605  }
606  else if (obedit_type == -1) {
607  /* Object mode */
608  t->tsnap.modeSelect = SNAP_NOT_SELECTED;
609  }
610  else {
611  /* Increment if snap is not possible */
612  t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
613  }
614  }
615  else if (t->spacetype == SPACE_NODE) {
617  t->tsnap.modeSelect = SNAP_NOT_SELECTED;
618  }
619  else if (t->spacetype == SPACE_SEQ) {
620  /* We do our own snapping currently, so nothing here */
621  t->tsnap.mode = SCE_SNAP_MODE_GRID; /* Dummy, should we rather add a NOP mode? */
622  }
623  else {
624  /* Always increment outside of 3D view */
625  t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
626  }
627 
628  if (t->spacetype == SPACE_VIEW3D) {
629  if (t->tsnap.object_context == NULL) {
630  t->tsnap.use_backface_culling = snap_use_backface_culling(t);
631  t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
632  t->scene, 0, t->region, t->view);
633 
634  if (t->data_type == TC_MESH_VERTS) {
635  /* Ignore elements being transformed. */
637  t->tsnap.object_context,
638  (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
642  }
643  }
644  }
645 }
646 
648 {
649  ToolSettings *ts = t->settings;
650  short snap_target = t->settings->snap_target;
651 
652  resetSnapping(t);
653 
654  /* if snap property exists */
655  if (op && RNA_struct_find_property(op->ptr, "snap") &&
656  RNA_struct_property_is_set(op->ptr, "snap")) {
657  if (RNA_boolean_get(op->ptr, "snap")) {
658  t->modifiers |= MOD_SNAP;
659 
660  if (RNA_struct_property_is_set(op->ptr, "snap_target")) {
661  snap_target = RNA_enum_get(op->ptr, "snap_target");
662  }
663 
664  if (RNA_struct_property_is_set(op->ptr, "snap_point")) {
665  RNA_float_get_array(op->ptr, "snap_point", t->tsnap.snapPoint);
666  t->tsnap.status |= SNAP_FORCED | POINT_INIT;
667  }
668 
669  /* snap align only defined in specific cases */
670  if (RNA_struct_find_property(op->ptr, "snap_align")) {
671  t->tsnap.align = RNA_boolean_get(op->ptr, "snap_align");
672  RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
673  normalize_v3(t->tsnap.snapNormal);
674  }
675 
676  if (RNA_struct_find_property(op->ptr, "use_snap_project")) {
677  t->tsnap.project = RNA_boolean_get(op->ptr, "use_snap_project");
678  }
679 
680  if (RNA_struct_find_property(op->ptr, "use_snap_self")) {
681  t->tsnap.snap_self = RNA_boolean_get(op->ptr, "use_snap_self");
682  }
683  }
684  }
685  /* use scene defaults only when transform is modal */
686  else if (t->flag & T_MODAL) {
687  if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) {
688  if (transformModeUseSnap(t) && (ts->snap_flag & SCE_SNAP)) {
689  t->modifiers |= MOD_SNAP;
690  }
691 
692  t->tsnap.align = ((t->settings->snap_flag & SCE_SNAP_ROTATE) != 0);
693  t->tsnap.project = ((t->settings->snap_flag & SCE_SNAP_PROJECT) != 0);
694  t->tsnap.snap_self = !((t->settings->snap_flag & SCE_SNAP_NO_SELF) != 0);
695  t->tsnap.peel = ((t->settings->snap_flag & SCE_SNAP_PROJECT) != 0);
696  }
697  }
698 
699  t->tsnap.target = snap_target;
700 
702 }
703 
705 {
706  if (t->tsnap.object_context) {
707  ED_transform_snap_object_context_destroy(t->tsnap.object_context);
708  t->tsnap.object_context = NULL;
709  }
710 }
711 
713 {
714  t->tsnap.calcSnap = CalcSnapGeometry;
715 
716  switch (t->tsnap.target) {
718  t->tsnap.targetSnap = TargetSnapClosest;
719  break;
721  if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
722  t->tsnap.targetSnap = TargetSnapCenter;
723  break;
724  }
725  /* Can't do TARGET_CENTER with these modes,
726  * use TARGET_MEDIAN instead. */
729  t->tsnap.targetSnap = TargetSnapMedian;
730  break;
732  t->tsnap.targetSnap = TargetSnapActive;
733  break;
734  }
735 }
736 
738 {
739  /* Currently only 3D viewport works for snapping points. */
740  if (t->tsnap.status & POINT_INIT && t->spacetype == SPACE_VIEW3D) {
741  TransSnapPoint *p = MEM_callocN(sizeof(TransSnapPoint), "SnapPoint");
742 
743  t->tsnap.selectedPoint = p;
744 
745  copy_v3_v3(p->co, t->tsnap.snapPoint);
746 
747  BLI_addtail(&t->tsnap.points, p);
748 
749  t->tsnap.status |= MULTI_POINTS;
750  }
751 }
752 
754 {
755  eRedrawFlag status = TREDRAW_NOTHING;
756 
757  if (t->tsnap.status & MULTI_POINTS) {
758  TransSnapPoint *p, *closest_p = NULL;
759  float dist_min_sq = TRANSFORM_SNAP_MAX_PX;
760  const float mval_fl[2] = {t->mval[0], t->mval[1]};
761  float screen_loc[2];
762 
763  for (p = t->tsnap.points.first; p; p = p->next) {
764  float dist_sq;
765 
766  if (ED_view3d_project_float_global(t->region, p->co, screen_loc, V3D_PROJ_TEST_NOP) !=
767  V3D_PROJ_RET_OK) {
768  continue;
769  }
770 
771  dist_sq = len_squared_v2v2(mval_fl, screen_loc);
772 
773  if (dist_sq < dist_min_sq) {
774  closest_p = p;
775  dist_min_sq = dist_sq;
776  }
777  }
778 
779  if (closest_p) {
780  if (t->tsnap.selectedPoint != closest_p) {
781  status = TREDRAW_HARD;
782  }
783 
784  t->tsnap.selectedPoint = closest_p;
785  }
786  }
787 
788  return status;
789 }
790 
792 {
793  if (t->tsnap.status & MULTI_POINTS) {
795 
796  if (t->tsnap.selectedPoint) {
797  BLI_freelinkN(&t->tsnap.points, t->tsnap.selectedPoint);
798 
799  if (BLI_listbase_is_empty(&t->tsnap.points)) {
800  t->tsnap.status &= ~MULTI_POINTS;
801  }
802 
803  t->tsnap.selectedPoint = NULL;
804  }
805  }
806 }
807 
808 void getSnapPoint(const TransInfo *t, float vec[3])
809 {
810  if (t->tsnap.points.first) {
811  TransSnapPoint *p;
812  int total = 0;
813 
814  vec[0] = vec[1] = vec[2] = 0;
815 
816  for (p = t->tsnap.points.first; p; p = p->next, total++) {
817  add_v3_v3(vec, p->co);
818  }
819 
820  if (t->tsnap.status & POINT_INIT) {
821  add_v3_v3(vec, t->tsnap.snapPoint);
822  total++;
823  }
824 
825  mul_v3_fl(vec, 1.0f / total);
826  }
827  else {
828  copy_v3_v3(vec, t->tsnap.snapPoint);
829  }
830 }
831 
834 /* -------------------------------------------------------------------- */
838 static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
839 {
840  if (t->spacetype == SPACE_VIEW3D) {
841  float loc[3];
842  float no[3];
843  float mval[2];
844  bool found = false;
845  short snap_elem = 0;
846  float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */
847 
848  mval[0] = t->mval[0];
849  mval[1] = t->mval[1];
850 
853  zero_v3(no); /* objects won't set this */
854  snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no);
855  found = snap_elem != 0;
856  }
857  if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
858  found = peelObjectsTransform(
859  t, mval, (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, loc, no, NULL);
860 
861  if (found) {
862  snap_elem = SCE_SNAP_MODE_VOLUME;
863  }
864  }
865 
866  if (found == true) {
867  copy_v3_v3(t->tsnap.snapPoint, loc);
868  copy_v3_v3(t->tsnap.snapNormal, no);
869 
870  t->tsnap.status |= POINT_INIT;
871  }
872  else {
873  t->tsnap.status &= ~POINT_INIT;
874  }
875 
876  t->tsnap.snapElem = (char)snap_elem;
877  }
878  else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
879  if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
880  float co[2];
881 
882  UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
883 
884  uint objects_len = 0;
886  t->view_layer, NULL, &objects_len);
887 
888  float dist_sq = FLT_MAX;
890  t->scene, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
891  t->tsnap.snapPoint[0] *= t->aspect[0];
892  t->tsnap.snapPoint[1] *= t->aspect[1];
893 
894  t->tsnap.status |= POINT_INIT;
895  }
896  else {
897  t->tsnap.status &= ~POINT_INIT;
898  }
899  MEM_freeN(objects);
900  }
901  }
902  else if (t->spacetype == SPACE_NODE) {
903  if (t->tsnap.mode & (SCE_SNAP_MODE_NODE_X | SCE_SNAP_MODE_NODE_Y)) {
904  float loc[2];
905  float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */
906  char node_border;
907 
908  if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) {
909  copy_v2_v2(t->tsnap.snapPoint, loc);
910  t->tsnap.snapNodeBorder = node_border;
911 
912  t->tsnap.status |= POINT_INIT;
913  }
914  else {
915  t->tsnap.status &= ~POINT_INIT;
916  }
917  }
918  }
919 }
920 
923 /* -------------------------------------------------------------------- */
927 static void snap_target_median_impl(TransInfo *t, float r_median[3])
928 {
929  int i_accum = 0;
930 
931  zero_v3(r_median);
932 
934  TransData *td = tc->data;
935  int i;
936  float v[3];
937  zero_v3(v);
938 
939  for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
940  add_v3_v3(v, td->center);
941  }
942 
943  if (i == 0) {
944  /* Is this possible? */
945  continue;
946  }
947 
948  mul_v3_fl(v, 1.0 / i);
949 
950  if (tc->use_local_mat) {
951  mul_m4_v3(tc->mat, v);
952  }
953 
954  add_v3_v3(r_median, v);
955  i_accum++;
956  }
957 
958  mul_v3_fl(r_median, 1.0 / i_accum);
959 
960  // TargetSnapOffset(t, NULL);
961 }
962 
964 {
965  /* Only need to calculate once. */
966  if ((t->tsnap.status & TARGET_GRID_INIT) == 0) {
967  if (t->data_type == TC_CURSOR_VIEW3D) {
968  /* Use a fallback when transforming the cursor.
969  * In this case the center is _not_ derived from the cursor which is being transformed. */
970  copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc);
971  }
972  else if (t->around == V3D_AROUND_CURSOR) {
973  /* Use a fallback for cursor selection,
974  * this isn't useful as a global center for absolute grid snapping
975  * since its not based on the position of the selection. */
976  snap_target_median_impl(t, t->tsnap.snapTargetGrid);
977  }
978  else {
979  copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global);
980  }
981  t->tsnap.status |= TARGET_GRID_INIT;
982  }
983 }
984 
986 {
987  if (t->spacetype == SPACE_NODE && td != NULL) {
988  bNode *node = td->extra;
989  char border = t->tsnap.snapNodeBorder;
990  float width = BLI_rctf_size_x(&node->totr);
991  float height = BLI_rctf_size_y(&node->totr);
992 
993 #ifdef USE_NODE_CENTER
994  if (border & NODE_LEFT) {
995  t->tsnap.snapTarget[0] -= 0.5f * width;
996  }
997  if (border & NODE_RIGHT) {
998  t->tsnap.snapTarget[0] += 0.5f * width;
999  }
1000  if (border & NODE_BOTTOM) {
1001  t->tsnap.snapTarget[1] -= 0.5f * height;
1002  }
1003  if (border & NODE_TOP) {
1004  t->tsnap.snapTarget[1] += 0.5f * height;
1005  }
1006 #else
1007  if (border & NODE_LEFT) {
1008  t->tsnap.snapTarget[0] -= 0.0f;
1009  }
1010  if (border & NODE_RIGHT) {
1011  t->tsnap.snapTarget[0] += width;
1012  }
1013  if (border & NODE_BOTTOM) {
1014  t->tsnap.snapTarget[1] -= height;
1015  }
1016  if (border & NODE_TOP) {
1017  t->tsnap.snapTarget[1] += 0.0f;
1018  }
1019 #endif
1020  }
1021 }
1022 
1024 {
1025  /* Only need to calculate once */
1026  if ((t->tsnap.status & TARGET_INIT) == 0) {
1027  copy_v3_v3(t->tsnap.snapTarget, t->center_global);
1029 
1030  t->tsnap.status |= TARGET_INIT;
1031  }
1032 }
1033 
1035 {
1036  /* Only need to calculate once */
1037  if ((t->tsnap.status & TARGET_INIT) == 0) {
1038  if (calculateCenterActive(t, true, t->tsnap.snapTarget)) {
1040 
1041  t->tsnap.status |= TARGET_INIT;
1042  }
1043  /* No active, default to median */
1044  else {
1045  t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
1046  t->tsnap.targetSnap = TargetSnapMedian;
1048  }
1049  }
1050 }
1051 
1053 {
1054  /* Only need to calculate once. */
1055  if ((t->tsnap.status & TARGET_INIT) == 0) {
1056  snap_target_median_impl(t, t->tsnap.snapTarget);
1057  t->tsnap.status |= TARGET_INIT;
1058  }
1059 }
1060 
1062 {
1063  /* Only valid if a snap point has been selected. */
1064  if (t->tsnap.status & POINT_INIT) {
1065  float dist_closest = 0.0f;
1066  TransData *closest = NULL;
1067 
1068  /* Object mode */
1069  if (t->options & CTX_OBJECT) {
1070  int i;
1072  TransData *td = tc->data;
1073  for (td = tc->data, i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
1074  const BoundBox *bb = NULL;
1075 
1076  if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
1077  bb = BKE_object_boundbox_get(td->ob);
1078  }
1079 
1080  /* use boundbox if possible */
1081  if (bb) {
1082  int j;
1083 
1084  for (j = 0; j < 8; j++) {
1085  float loc[3];
1086  float dist;
1087 
1088  copy_v3_v3(loc, bb->vec[j]);
1089  mul_m4_v3(td->ext->obmat, loc);
1090 
1091  dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
1092 
1093  if ((dist != TRANSFORM_DIST_INVALID) &&
1094  (closest == NULL || fabsf(dist) < fabsf(dist_closest))) {
1095  copy_v3_v3(t->tsnap.snapTarget, loc);
1096  closest = td;
1097  dist_closest = dist;
1098  }
1099  }
1100  }
1101  /* use element center otherwise */
1102  else {
1103  float loc[3];
1104  float dist;
1105 
1106  copy_v3_v3(loc, td->center);
1107 
1108  dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
1109 
1110  if ((dist != TRANSFORM_DIST_INVALID) &&
1111  (closest == NULL || fabsf(dist) < fabsf(dist_closest))) {
1112  copy_v3_v3(t->tsnap.snapTarget, loc);
1113  closest = td;
1114  }
1115  }
1116  }
1117  }
1118  }
1119  else {
1121  TransData *td = tc->data;
1122  int i;
1123  for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
1124  float loc[3];
1125  float dist;
1126 
1127  copy_v3_v3(loc, td->center);
1128 
1129  if (tc->use_local_mat) {
1130  mul_m4_v3(tc->mat, loc);
1131  }
1132 
1133  dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
1134 
1135  if ((dist != TRANSFORM_DIST_INVALID) &&
1136  (closest == NULL || fabsf(dist) < fabsf(dist_closest))) {
1137  copy_v3_v3(t->tsnap.snapTarget, loc);
1138  closest = td;
1139  dist_closest = dist;
1140  }
1141  }
1142  }
1143  }
1144 
1146 
1147  t->tsnap.status |= TARGET_INIT;
1148  }
1149 }
1150 
1153 /* -------------------------------------------------------------------- */
1158  TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3])
1159 {
1160  float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global;
1162  t->tsnap.object_context,
1163  t->depsgraph,
1164  t->settings->snap_mode,
1165  &(const struct SnapObjectParams){
1166  .snap_select = t->tsnap.modeSelect,
1167  .use_object_edit_cage = (t->flag & T_EDIT) != 0,
1168  .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE,
1169  .use_backface_culling = t->tsnap.use_backface_culling,
1170  },
1171  mval,
1172  target,
1173  dist_px,
1174  r_loc,
1175  r_no,
1176  NULL,
1177  NULL,
1178  NULL);
1179 }
1180 
1183 /* -------------------------------------------------------------------- */
1188  const float mval[2],
1189  const bool use_peel_object,
1190  /* return args */
1191  float r_loc[3],
1192  float r_no[3],
1193  float *r_thickness)
1194 {
1195  ListBase depths_peel = {0};
1197  t->tsnap.object_context,
1198  t->depsgraph,
1199  &(const struct SnapObjectParams){
1200  .snap_select = t->tsnap.modeSelect,
1201  .use_object_edit_cage = (t->flag & T_EDIT) != 0,
1202  },
1203  mval,
1204  -1.0f,
1205  false,
1206  &depths_peel);
1207 
1208  if (!BLI_listbase_is_empty(&depths_peel)) {
1209  /* At the moment we only use the hits of the first object */
1210  struct SnapObjectHitDepth *hit_min = depths_peel.first;
1211  for (struct SnapObjectHitDepth *iter = hit_min->next; iter; iter = iter->next) {
1212  if (iter->depth < hit_min->depth) {
1213  hit_min = iter;
1214  }
1215  }
1216  struct SnapObjectHitDepth *hit_max = NULL;
1217 
1218  if (use_peel_object) {
1219  /* if peeling objects, take the first and last from each object */
1220  hit_max = hit_min;
1221  for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) {
1222  if ((iter->depth > hit_max->depth) && (iter->ob_uuid == hit_min->ob_uuid)) {
1223  hit_max = iter;
1224  }
1225  }
1226  }
1227  else {
1228  /* otherwise, pair first with second and so on */
1229  for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) {
1230  if ((iter != hit_min) && (iter->ob_uuid == hit_min->ob_uuid)) {
1231  if (hit_max == NULL) {
1232  hit_max = iter;
1233  }
1234  else if (iter->depth < hit_max->depth) {
1235  hit_max = iter;
1236  }
1237  }
1238  }
1239  /* in this case has only one hit. treat as raycast */
1240  if (hit_max == NULL) {
1241  hit_max = hit_min;
1242  }
1243  }
1244 
1245  mid_v3_v3v3(r_loc, hit_min->co, hit_max->co);
1246 
1247  if (r_thickness) {
1248  *r_thickness = hit_max->depth - hit_min->depth;
1249  }
1250 
1251  /* XXX, is there a correct normal in this case ???, for now just z up */
1252  r_no[0] = 0.0;
1253  r_no[1] = 0.0;
1254  r_no[2] = 1.0;
1255 
1256  BLI_freelistN(&depths_peel);
1257  return true;
1258  }
1259  return false;
1260 }
1261 
1264 /* -------------------------------------------------------------------- */
1268 static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select)
1269 {
1270  /* node is use for snapping only if a) snap mode matches and b) node is inside the view */
1271  return ((snap_select == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
1272  (snap_select == SNAP_ALL && !(node->flag & NODE_ACTIVE))) &&
1273  (node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin &&
1274  node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin);
1275 }
1276 
1277 static NodeBorder snapNodeBorder(int snap_node_mode)
1278 {
1279  NodeBorder flag = 0;
1280  if (snap_node_mode & SCE_SNAP_MODE_NODE_X) {
1281  flag |= NODE_LEFT | NODE_RIGHT;
1282  }
1283  if (snap_node_mode & SCE_SNAP_MODE_NODE_Y) {
1284  flag |= NODE_TOP | NODE_BOTTOM;
1285  }
1286  return flag;
1287 }
1288 
1289 static bool snapNode(ToolSettings *ts,
1290  SpaceNode *UNUSED(snode),
1291  ARegion *region,
1292  bNode *node,
1293  const int mval[2],
1294  float r_loc[2],
1295  float *r_dist_px,
1296  char *r_node_border)
1297 {
1298  View2D *v2d = &region->v2d;
1300  bool retval = false;
1301  rcti totr;
1302  int new_dist;
1303 
1304  UI_view2d_view_to_region_rcti(v2d, &node->totr, &totr);
1305 
1306  if (border & NODE_LEFT) {
1307  new_dist = abs(totr.xmin - mval[0]);
1308  if (new_dist < *r_dist_px) {
1309  UI_view2d_region_to_view(v2d, totr.xmin, mval[1], &r_loc[0], &r_loc[1]);
1310  *r_dist_px = new_dist;
1311  *r_node_border = NODE_LEFT;
1312  retval = true;
1313  }
1314  }
1315 
1316  if (border & NODE_RIGHT) {
1317  new_dist = abs(totr.xmax - mval[0]);
1318  if (new_dist < *r_dist_px) {
1319  UI_view2d_region_to_view(v2d, totr.xmax, mval[1], &r_loc[0], &r_loc[1]);
1320  *r_dist_px = new_dist;
1321  *r_node_border = NODE_RIGHT;
1322  retval = true;
1323  }
1324  }
1325 
1326  if (border & NODE_BOTTOM) {
1327  new_dist = abs(totr.ymin - mval[1]);
1328  if (new_dist < *r_dist_px) {
1329  UI_view2d_region_to_view(v2d, mval[0], totr.ymin, &r_loc[0], &r_loc[1]);
1330  *r_dist_px = new_dist;
1331  *r_node_border = NODE_BOTTOM;
1332  retval = true;
1333  }
1334  }
1335 
1336  if (border & NODE_TOP) {
1337  new_dist = abs(totr.ymax - mval[1]);
1338  if (new_dist < *r_dist_px) {
1339  UI_view2d_region_to_view(v2d, mval[0], totr.ymax, &r_loc[0], &r_loc[1]);
1340  *r_dist_px = new_dist;
1341  *r_node_border = NODE_TOP;
1342  retval = true;
1343  }
1344  }
1345 
1346  return retval;
1347 }
1348 
1349 static bool snapNodes(ToolSettings *ts,
1350  SpaceNode *snode,
1351  ARegion *region,
1352  const int mval[2],
1353  eSnapSelect snap_select,
1354  float r_loc[2],
1355  float *r_dist_px,
1356  char *r_node_border)
1357 {
1358  bNodeTree *ntree = snode->edittree;
1359  bNode *node;
1360  bool retval = false;
1361 
1362  *r_node_border = 0;
1363 
1364  for (node = ntree->nodes.first; node; node = node->next) {
1365  if (snapNodeTest(&region->v2d, node, snap_select)) {
1366  retval |= snapNode(ts, snode, region, node, mval, r_loc, r_dist_px, r_node_border);
1367  }
1368  }
1369 
1370  return retval;
1371 }
1372 
1374  TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border)
1375 {
1376  return snapNodes(t->settings,
1377  t->area->spacedata.first,
1378  t->region,
1379  mval,
1380  t->tsnap.modeSelect,
1381  r_loc,
1382  r_dist_px,
1383  r_node_border);
1384 }
1385 
1388 /* -------------------------------------------------------------------- */
1392 /* This function is used by Animation Editor specific transform functions to do
1393  * the Snap Keyframe to Nearest Frame/Marker
1394  */
1396  const eAnimEdit_AutoSnap autosnap,
1397  const bool is_frame_value,
1398  const float delta,
1399  float *r_val)
1400 {
1401  double val = delta;
1402  switch (autosnap) {
1403  case SACTSNAP_STEP:
1404  case SACTSNAP_FRAME:
1405  val = floor(val + 0.5);
1406  break;
1407  case SACTSNAP_MARKER:
1408  /* snap to nearest marker */
1409  /* TODO: need some more careful checks for where data comes from. */
1410  val = ED_markers_find_nearest_marker_time(&t->scene->markers, (float)val);
1411  break;
1412  case SACTSNAP_SECOND:
1413  case SACTSNAP_TSTEP: {
1414  /* second step */
1415  const Scene *scene = t->scene;
1416  const double secf = FPS;
1417  val = floor((val / secf) + 0.5);
1418  if (is_frame_value) {
1419  val *= secf;
1420  }
1421  break;
1422  }
1423  case SACTSNAP_OFF: {
1424  break;
1425  }
1426  }
1427  *r_val = (float)val;
1428 }
1429 
1430 /*================================================================*/
1431 
1432 void snapSequenceBounds(TransInfo *t, const int mval[2])
1433 {
1434  /* Reuse increment, strictly speaking could be another snap mode, but leave as is. */
1435  if (!(t->modifiers & MOD_SNAP_INVERT)) {
1436  return;
1437  }
1438 
1439  /* Convert to frame range. */
1440  float xmouse, ymouse;
1441  UI_view2d_region_to_view(&t->region->v2d, mval[0], mval[1], &xmouse, &ymouse);
1442  const int frame_curr = round_fl_to_int(xmouse);
1443 
1444  /* Now find the closest sequence. */
1445  const int frame_near = SEQ_time_find_next_prev_edit(
1446  t->scene, frame_curr, SEQ_SIDE_BOTH, true, false, true);
1447 
1448  const int frame_snap = transform_convert_sequencer_get_snap_bound(t);
1449  t->values[0] = frame_near - frame_snap;
1450 }
1451 
1452 static void snap_grid_apply(
1453  TransInfo *t, const int max_index, const float grid_dist, const float loc[3], float r_out[3])
1454 {
1455  BLI_assert(max_index <= 2);
1457  const float *center_global = t->tsnap.snapTargetGrid;
1458  const float *asp = t->aspect;
1459 
1460  float in[3];
1461  if (t->con.mode & CON_APPLY) {
1462  BLI_assert(t->tsnap.snapElem == 0);
1463  t->con.applyVec(t, NULL, NULL, loc, in);
1464  }
1465  else {
1466  copy_v3_v3(in, loc);
1467  }
1468 
1469  for (int i = 0; i <= max_index; i++) {
1470  const float iter_fac = grid_dist * asp[i];
1471  r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i];
1472  }
1473 }
1474 
1475 bool transform_snap_grid(TransInfo *t, float *val)
1476 {
1477  if (!activeSnap(t)) {
1478  return false;
1479  }
1480 
1481  if ((!(t->tsnap.mode & SCE_SNAP_MODE_GRID)) || validSnap(t)) {
1482  /* Don't do grid snapping if there is a valid snap point. */
1483  return false;
1484  }
1485 
1486  if (t->spacetype != SPACE_VIEW3D) {
1487  return false;
1488  }
1489 
1490  if (t->mode != TFM_TRANSLATION) {
1491  return false;
1492  }
1493 
1494  float grid_dist = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
1495 
1496  /* Early bailing out if no need to snap */
1497  if (grid_dist == 0.0f) {
1498  return false;
1499  }
1500 
1501  snap_grid_apply(t, t->idx_max, grid_dist, val, val);
1502  t->tsnap.snapElem = SCE_SNAP_MODE_GRID;
1503  return true;
1504 }
1505 
1507  const int max_index,
1508  const float increment_val,
1509  const float aspect[3],
1510  const float loc[3],
1511  float r_out[3])
1512 {
1513  /* relative snapping in fixed increments */
1514  for (int i = 0; i <= max_index; i++) {
1515  const float iter_fac = increment_val * aspect[i];
1516  r_out[i] = iter_fac * roundf(loc[i] / iter_fac);
1517  }
1518 }
1519 
1521  int max_index,
1522  const float increment_dist,
1523  float *r_val)
1524 {
1526  BLI_assert(max_index <= 2);
1527 
1528  /* Early bailing out if no need to snap */
1529  if (increment_dist == 0.0f) {
1530  return;
1531  }
1532 
1533  float asp_local[3] = {1, 1, 1};
1534  const bool use_aspect = ELEM(t->mode, TFM_TRANSLATION);
1535  const float *asp = use_aspect ? t->aspect : asp_local;
1536 
1537  if (use_aspect) {
1538  /* custom aspect for fcurve */
1539  if (t->spacetype == SPACE_GRAPH) {
1540  View2D *v2d = &t->region->v2d;
1541  Scene *scene = t->scene;
1542  SpaceGraph *sipo = t->area->spacedata.first;
1544  v2d, scene, sipo->flag & SIPO_DRAWTIME);
1545  asp_local[1] = UI_view2d_grid_resolution_y__values(v2d);
1546  asp = asp_local;
1547  }
1548  }
1549 
1550  snap_increment_apply_ex(t, max_index, increment_dist, asp, r_val, r_val);
1551 }
1552 
1553 bool transform_snap_increment_ex(TransInfo *t, bool use_local_space, float *r_val)
1554 {
1555  if (!activeSnap(t)) {
1556  return false;
1557  }
1558 
1559  if (!(t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && !doForceIncrementSnap(t)) {
1560  return false;
1561  }
1562 
1563  if (t->spacetype != SPACE_VIEW3D && validSnap(t)) {
1564  /* Only do something if using absolute or incremental grid snapping
1565  * and there is no valid snap point. */
1566  return false;
1567  }
1568 
1569  if (use_local_space) {
1570  BLI_assert(t->idx_max == 2);
1571  mul_m3_v3(t->spacemtx_inv, r_val);
1572  }
1573 
1574  float increment_dist = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
1575  snap_increment_apply(t, t->idx_max, increment_dist, r_val);
1576 
1577  if (use_local_space) {
1578  mul_m3_v3(t->spacemtx, r_val);
1579  }
1580 
1581  return true;
1582 }
1583 
1585 {
1586  return transform_snap_increment_ex(t, false, r_val);
1587 }
1588 
1591 /* -------------------------------------------------------------------- */
1596  const float p1[3],
1597  const float p2[3])
1598 {
1599  return len_squared_v3v3(p1, p2);
1600 }
1601 
typedef float(TangentPoint)[2]
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:769
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:434
General operations, lookup, etc. for blender objects.
void BKE_object_eval_transform_all(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *object)
struct BoundBox * BKE_object_boundbox_get(struct Object *ob)
Definition: object.c:3817
bool BKE_scene_uses_blender_workbench(const struct Scene *scene)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define ATTR_FALLTHROUGH
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:281
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
MINLINE int round_fl_to_int(float a)
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3])
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:161
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:165
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
#define ELEM(...)
#define POINTER_FROM_UINT(i)
eAnimEdit_AutoSnap
@ SACTSNAP_OFF
@ SACTSNAP_SECOND
@ SACTSNAP_TSTEP
@ SACTSNAP_MARKER
@ SACTSNAP_STEP
@ SACTSNAP_FRAME
#define NODE_SELECT
#define NODE_ACTIVE
@ OB_SOLID
@ OB_RENDER
@ OB_MODE_PARTICLE_EDIT
@ OB_LATTICE
@ OB_MBALL
@ OB_ARMATURE
@ OB_MESH
@ OB_CURVE
#define SCE_SNAP_MODE_NODE_Y
#define SCE_SNAP_TARGET_CLOSEST
#define SCE_SNAP_PEEL_OBJECT
#define SCE_SNAP
#define SCE_SNAP_MODE_FACE
#define SCE_SNAP_TARGET_ACTIVE
#define SCE_SNAP_MODE_NODE_X
#define SCE_SNAP_ABS_GRID
#define SCE_SNAP_TARGET_CENTER
#define SCE_SNAP_MODE_VOLUME
#define SCE_SNAP_MODE_EDGE_PERPENDICULAR
#define SCE_SNAP_MODE_EDGE_MIDPOINT
#define SCE_SNAP_NO_SELF
#define SCE_SNAP_TARGET_MEDIAN
#define SCE_SNAP_ROTATE
@ SCE_SNAP_TRANSFORM_MODE_SCALE
@ SCE_SNAP_TRANSFORM_MODE_ROTATE
@ SCE_SNAP_TRANSFORM_MODE_TRANSLATE
#define SCE_SNAP_PROJECT
#define FPS
#define SCE_SNAP_MODE_VERTEX
#define SCE_SNAP_BACKFACE_CULLING
#define SCE_SNAP_MODE_GRID
#define SCE_SNAP_MODE_EDGE
#define SCE_SNAP_MODE_INCREMENT
@ SPACE_NODE
@ SPACE_SEQ
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SIPO_DRAWTIME
@ V3D_AROUND_CURSOR
@ V3D_SHADING_BACKFACE_CULLING
void ED_node_draw_snap(struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos)
Definition: drawnode.c:4117
NodeBorder
Definition: ED_node.h:44
@ NODE_LEFT
Definition: ED_node.h:47
@ NODE_RIGHT
Definition: ED_node.h:48
@ NODE_BOTTOM
Definition: ED_node.h:46
@ NODE_TOP
Definition: ED_node.h:45
@ TFM_RESIZE
Definition: ED_transform.h:48
@ TFM_EDGE_SLIDE
Definition: ED_transform.h:74
@ TFM_VERT_SLIDE
Definition: ED_transform.h:75
@ TFM_ROTATION
Definition: ED_transform.h:47
@ TFM_TRANSLATION
Definition: ED_transform.h:46
SnapObjectContext * ED_transform_snap_object_context_create_view3d(struct Scene *scene, int flag, const struct ARegion *region, const struct View3D *v3d)
void ED_transform_snap_object_context_set_editmesh_callbacks(SnapObjectContext *sctx, bool(*test_vert_fn)(struct BMVert *, void *user_data), bool(*test_edge_fn)(struct BMEdge *, void *user_data), bool(*test_face_fn)(struct BMFace *, void *user_data), void *user_data)
bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx, struct Depsgraph *depsgraph, const struct SnapObjectParams *params, const float mval[2], float ray_depth, bool sort, ListBase *r_hit_list)
short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, struct Depsgraph *depsgraph, const unsigned short 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, struct Object **r_ob, float r_obmat[4][4])
bool ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, struct Depsgraph *depsgraph, const unsigned short 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])
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
bool ED_uvedit_nearest_uv_multi(const struct Scene *scene, struct Object **objects, const uint objects_len, const float co[2], float *dist_sq, float r_uv[2])
float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3])
@ V3D_PROJ_TEST_NOP
Definition: ED_view3d.h:193
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:176
void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned int pos)
Definition: drawobject.c:90
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region, const float co[3], float r_co[2], const eV3DProjTest flag)
void immUniformColor4ubv(const unsigned char rgba[4])
void immUnbindProgram(void)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat(void)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:171
@ GPU_SHADER_3D_UNIFORM_COLOR
Definition: GPU_shader.h:200
@ GPU_BLEND_NONE
Definition: GPU_state.h:55
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:57
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:55
@ GPU_DEPTH_LESS_EQUAL
Definition: GPU_state.h:81
@ GPU_DEPTH_NONE
Definition: GPU_state.h:78
void GPU_depth_test(eGPUDepthTest test)
Definition: gpu_state.cc:75
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
Platform independent time functions.
#define C
Definition: RandGen.cpp:39
@ SEQ_SIDE_BOTH
Definition: SEQ_sequencer.h:43
@ TH_TRANSFORM
Definition: UI_resources.h:92
@ TH_VERTEX_SIZE
Definition: UI_resources.h:97
@ TH_SELECT
Definition: UI_resources.h:88
@ TH_ACTIVE
Definition: UI_resources.h:89
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
Definition: resources.c:1350
float UI_GetThemeValuef(int colorid)
Definition: resources.c:1164
void UI_view2d_view_to_region_rcti(const struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL()
float UI_view2d_grid_resolution_x__frames_or_seconds(const struct View2D *v2d, const struct Scene *scene, bool display_seconds)
Definition: view2d_draw.c:445
float UI_view2d_grid_resolution_y__values(const struct View2D *v2d)
Definition: view2d_draw.c:455
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
Definition: anim_markers.c:193
bool BM_elem_cb_check_hflag_disabled(BMElem *ele, void *user_data)
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
bool closest(btVector3 &v)
OperationNode * node
Scene scene
void * user_data
bNodeTree * ntree
uint pos
uint col
IconTextureDrawCall normal
IconTextureDrawCall border
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:6685
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
void ED_gizmotypes_snap_3d_draw_util(RegionView3D *rv3d, const float loc_prev[3], const float loc_curr[3], const float normal[3], const uchar color_line[4], const uchar color_point[4], const short snap_elem_type)
Definition: snap3d_gizmo.c:181
int SEQ_time_find_next_prev_edit(Scene *scene, int timeline_frame, const short side, const bool do_skip_mute, const bool do_center, const bool do_unselected)
Definition: strip_time.c:270
struct BMVert * v
Definition: bmesh_class.h:165
struct BMLoop * next
Definition: bmesh_class.h:245
struct Object * object
float vec[8][3]
void * first
Definition: DNA_listBase.h:47
float obmat[4][4]
float viewinv[4][4]
struct SnapObjectHitDepth * next
struct bNodeTree * edittree
char snap_transform_mode_flag
float smtx[3][3]
float axismtx[3][3]
TransDataExtension * ext
struct Object * ob
float co[3]
Definition: transform.h:296
struct TransSnapPoint * next
Definition: transform.h:295
View3DShading shading
struct Base * basact
ListBase nodes
float xmax
Definition: DNA_vec_types.h:85
float xmin
Definition: DNA_vec_types.h:85
float ymax
Definition: DNA_vec_types.h:86
float ymin
Definition: DNA_vec_types.h:86
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79
short shift
Definition: WM_types.h:618
short type
Definition: WM_types.h:577
struct PointerRNA * ptr
double PIL_check_seconds_timer(void)
Definition: time.c:80
bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot)
@ TARGET_GRID_INIT
Definition: transform.h:169
@ POINT_INIT
Definition: transform.h:170
@ MULTI_POINTS
Definition: transform.h:171
@ SNAP_FORCED
Definition: transform.h:166
@ TARGET_INIT
Definition: transform.h:167
@ CON_APPLY
Definition: transform.h:177
@ CTX_CURSOR
Definition: transform.h:80
@ CTX_OBMODE_XFORM_OBDATA
Definition: transform.h:94
@ CTX_OBJECT
Definition: transform.h:85
@ CTX_GPENCIL_STROKES
Definition: transform.h:82
@ CTX_CAMERA
Definition: transform.h:79
@ MOD_SNAP_INVERT
Definition: transform.h:160
@ MOD_PRECISION
Definition: transform.h:158
@ MOD_SNAP
Definition: transform.h:159
eRedrawFlag
Definition: transform.h:197
@ TREDRAW_NOTHING
Definition: transform.h:198
@ TREDRAW_HARD
Definition: transform.h:199
@ T_MODAL
Definition: transform.h:132
@ T_NO_PROJECT
Definition: transform.h:135
@ T_PROP_EDIT
Definition: transform.h:111
@ T_EDIT
Definition: transform.h:102
#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t)
Definition: transform.h:810
#define TRANSFORM_SNAP_MAX_PX
Definition: transform.h:803
#define TRANSFORM_DIST_INVALID
Definition: transform.h:804
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition: transform.h:813
@ TC_CURSOR_VIEW3D
Definition: transform.h:220
@ TC_MESH_VERTS
Definition: transform.h:227
conversion and adaptation of different datablocks to a common struct.
int transform_convert_sequencer_get_snap_bound(TransInfo *t)
@ TD_SELECTED
@ TD_SKIP
void constraintTransLim(TransInfo *t, TransData *td)
void snapSequenceBounds(TransInfo *t, const int mval[2])
bool transformModeUseSnap(const TransInfo *t)
bool usingSnappingNormal(const TransInfo *t)
static void TargetSnapCenter(TransInfo *t)
bool transform_snap_grid(TransInfo *t, float *val)
static void CalcSnapGeometry(TransInfo *t, float *vec)
void applySnapping(TransInfo *t, float *vec)
void applyProject(TransInfo *t)
bool transform_snap_increment(TransInfo *t, float *r_val)
float transform_snap_distance_len_squared_fn(TransInfo *UNUSED(t), const float p1[3], const float p2[3])
static void snap_target_median_impl(TransInfo *t, float r_median[3])
void snapFrameTransform(TransInfo *t, const eAnimEdit_AutoSnap autosnap, const bool is_frame_value, const float delta, float *r_val)
static void TargetSnapActive(TransInfo *t)
void addSnapPoint(TransInfo *t)
bool validSnap(const TransInfo *t)
void freeSnapping(TransInfo *t)
eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
bool transform_snap_increment_ex(TransInfo *t, bool use_local_space, float *r_val)
bool snapNodesTransform(TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border)
static void snap_grid_apply(TransInfo *t, const int max_index, const float grid_dist, const float loc[3], float r_out[3])
static void setSnappingCallback(TransInfo *t)
void removeSnapPoint(TransInfo *t)
bool peelObjectsTransform(TransInfo *t, const float mval[2], const bool use_peel_object, float r_loc[3], float r_no[3], float *r_thickness)
static void TargetSnapMedian(TransInfo *t)
void drawSnapping(const struct bContext *C, TransInfo *t)
static void snap_increment_apply_ex(TransInfo *UNUSED(t), const int max_index, const float increment_val, const float aspect[3], const float loc[3], float r_out[3])
static void TargetSnapOffset(TransInfo *t, TransData *td)
void getSnapPoint(const TransInfo *t, float vec[3])
static bool snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *region, const int mval[2], eSnapSelect snap_select, float r_loc[2], float *r_dist_px, char *r_node_border)
short snapObjectsTransform(TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3])
static void TargetSnapClosest(TransInfo *t)
static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select)
static bool doForceIncrementSnap(const TransInfo *t)
eRedrawFlag updateSelectedSnapPoint(TransInfo *t)
static bool snap_use_backface_culling(const TransInfo *t)
static bool bm_edge_is_snap_target(BMEdge *e, void *UNUSED(user_data))
static bool snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *region, bNode *node, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border)
static void snap_target_grid_ensure(TransInfo *t)
void initSnapping(TransInfo *t, wmOperator *op)
static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
void applyGridAbsolute(TransInfo *t)
bool validSnappingNormal(const TransInfo *t)
static void initSnappingMode(TransInfo *t)
void resetSnapping(TransInfo *t)
static void snap_increment_apply(TransInfo *t, int max_index, const float increment_dist, float *r_val)
static NodeBorder snapNodeBorder(int snap_node_mode)
bool activeSnap(const TransInfo *t)
#define SNAP_MIN_DISTANCE
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186
ccl_device_inline float2 floor(const float2 &a)
@ MOUSEMOVE