Blender  V3.3
transform_snap.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include <float.h>
9 
10 #include "PIL_time.h"
11 
13 
14 #include "BLI_blenlib.h"
15 #include "BLI_math.h"
16 
17 #include "GPU_immediate.h"
18 #include "GPU_matrix.h"
19 #include "GPU_state.h"
20 
21 #include "BKE_context.h"
22 #include "BKE_editmesh.h"
23 #include "BKE_layer.h"
24 #include "BKE_object.h"
25 #include "BKE_scene.h"
26 
27 #include "RNA_access.h"
28 
29 #include "WM_api.h"
30 #include "WM_types.h"
31 
32 #include "ED_gizmo_library.h"
33 #include "ED_markers.h"
34 #include "ED_node.h"
36 #include "ED_uvedit.h"
37 #include "ED_view3d.h"
38 
39 #include "UI_resources.h"
40 #include "UI_view2d.h"
41 
42 #include "SEQ_iterator.h"
43 #include "SEQ_sequencer.h"
44 #include "SEQ_time.h"
45 
46 #include "MEM_guardedalloc.h"
47 
48 #include "transform.h"
49 #include "transform_convert.h"
50 #include "transform_snap.h"
51 
52 static bool doForceIncrementSnap(const TransInfo *t);
53 
54 /* this should be passed as an arg for use in snap functions */
55 #undef BASACT
56 
57 /* use half of flt-max so we can scale up without an exception */
58 
59 /* -------------------------------------------------------------------- */
63 static void setSnappingCallback(TransInfo *t);
64 
65 /* static void CalcSnapGrid(TransInfo *t, float *vec); */
66 static void snap_calc_view3d_fn(TransInfo *t, float *vec);
67 static void snap_calc_uv_fn(TransInfo *t, float *vec);
68 static void snap_calc_node_fn(TransInfo *t, float *vec);
69 static void snap_calc_sequencer_fn(TransInfo *t, float *vec);
70 
71 static void TargetSnapMedian(TransInfo *t);
72 static void TargetSnapCenter(TransInfo *t);
73 static void TargetSnapClosest(TransInfo *t);
74 static void TargetSnapActive(TransInfo *t);
75 
78 /* -------------------------------------------------------------------- */
82 static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select);
83 static NodeBorder snapNodeBorder(eSnapMode snap_node_mode);
84 
85 #if 0
86 int BIF_snappingSupported(Object *obedit)
87 {
88  int status = 0;
89 
90  /* only support object mesh, armature, curves */
91  if (obedit == NULL || ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVES_LEGACY, OB_LATTICE, OB_MBALL)) {
92  status = 1;
93  }
94 
95  return status;
96 }
97 #endif
98 
100 {
101  BLI_assert(t->spacetype == SPACE_VIEW3D);
102  View3D *v3d = t->view;
103  if ((v3d->shading.type == OB_SOLID) && (v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING)) {
104  return true;
105  }
106  if (v3d->shading.type == OB_RENDER &&
107  (t->scene->display.shading.flag & V3D_SHADING_BACKFACE_CULLING) &&
109  return true;
110  }
111  if (t->settings->snap_flag & SCE_SNAP_BACKFACE_CULLING) {
112  return true;
113  }
114  return false;
115 }
116 
117 bool validSnap(const TransInfo *t)
118 {
119  return (t->tsnap.status & (POINT_INIT | TARGET_INIT)) == (POINT_INIT | TARGET_INIT) ||
120  (t->tsnap.status & (MULTI_POINTS | TARGET_INIT)) == (MULTI_POINTS | TARGET_INIT);
121 }
122 
123 bool activeSnap(const TransInfo *t)
124 {
125  return ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP) ||
126  ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT);
127 }
128 
130 {
131  if (!activeSnap(t) || (t->flag & T_NO_PROJECT)) {
132  return false;
133  }
134 
135  if (!(t->tsnap.project || (t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST))) {
136  return false;
137  }
138 
139  if (doForceIncrementSnap(t)) {
140  return false;
141  }
142 
143  return true;
144 }
145 
147 {
148  if (!activeSnap(t)) {
149  return false;
150  }
151 
152  if (t->tsnap.mode == SCE_SNAP_MODE_FACE_RAYCAST && t->tsnap.project) {
153  return false;
154  }
155 
156  if (t->tsnap.mode == SCE_SNAP_MODE_FACE_NEAREST) {
157  return false;
158  }
159 
160  if (doForceIncrementSnap(t)) {
161  return false;
162  }
163 
164  return true;
165 }
166 
168 {
169  ToolSettings *ts = t->settings;
170  if (t->mode == TFM_TRANSLATION) {
172  }
173  if (t->mode == TFM_ROTATION) {
175  }
176  if (t->mode == TFM_RESIZE) {
178  }
180  return true;
181  }
182 
183  return false;
184 }
185 
186 static bool doForceIncrementSnap(const TransInfo *t)
187 {
188  return !transformModeUseSnap(t);
189 }
190 
191 void drawSnapping(const struct bContext *C, TransInfo *t)
192 {
193  uchar col[4], selectedCol[4], activeCol[4];
194  if (!activeSnap(t)) {
195  return;
196  }
197 
198  bool draw_target = (t->spacetype == SPACE_VIEW3D) && (t->tsnap.status & TARGET_INIT) &&
199  (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
200 
201  if (!(draw_target || validSnap(t))) {
202  return;
203  }
204 
205  if (t->spacetype == SPACE_SEQ) {
207  col[3] = 128;
208  }
209  else if (t->spacetype != SPACE_IMAGE) {
211  col[3] = 128;
212 
213  UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
214  selectedCol[3] = 128;
215 
216  UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
217  activeCol[3] = 192;
218  }
219 
220  if (t->spacetype == SPACE_VIEW3D) {
221  const float *loc_cur = NULL;
222  const float *loc_prev = NULL;
223  const float *normal = NULL;
224 
226 
228  if (!BLI_listbase_is_empty(&t->tsnap.points)) {
229  /* Draw snap points. */
230 
231  float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE);
232  float view_inv[4][4];
233  copy_m4_m4(view_inv, rv3d->viewinv);
234 
237 
239 
240  LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) {
241  if (p == t->tsnap.selectedPoint) {
242  immUniformColor4ubv(selectedCol);
243  }
244  else {
246  }
247  imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos);
248  }
249 
251  }
252 
253  /* draw normal if needed */
255  normal = t->tsnap.snapNormal;
256  }
257 
258  if (draw_target) {
259  loc_prev = t->tsnap.snapTarget;
260  }
261 
262  if (validSnap(t)) {
263  loc_cur = t->tsnap.snapPoint;
264  }
265 
267  rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem);
268 
270  }
271  else if (t->spacetype == SPACE_IMAGE) {
273 
274  float x, y;
275  const float snap_point[2] = {
276  t->tsnap.snapPoint[0] / t->aspect[0],
277  t->tsnap.snapPoint[1] / t->aspect[1],
278  };
279  UI_view2d_view_to_region_fl(&t->region->v2d, UNPACK2(snap_point), &x, &y);
280  float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize;
281 
283  wmOrtho2_region_pixelspace(t->region);
284 
286  immUniformColor3ub(255, 255, 255);
287  imm_draw_circle_wire_2d(pos, x, y, radius, 8);
289 
291  }
292  else if (t->spacetype == SPACE_NODE) {
293  ARegion *region = CTX_wm_region(C);
294  TransSnapPoint *p;
295  float size;
296 
298 
300 
302 
304 
305  for (p = t->tsnap.points.first; p; p = p->next) {
306  if (p == t->tsnap.selectedPoint) {
307  immUniformColor4ubv(selectedCol);
308  }
309  else {
311  }
312 
313  ED_node_draw_snap(&region->v2d, p->co, size, 0, pos);
314  }
315 
316  if (t->tsnap.status & POINT_INIT) {
317  immUniformColor4ubv(activeCol);
318 
319  ED_node_draw_snap(&region->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos);
320  }
321 
323 
325  }
326  else if (t->spacetype == SPACE_SEQ) {
327  const ARegion *region = CTX_wm_region(C);
332  float pixelx = BLI_rctf_size_x(&region->v2d.cur) / BLI_rcti_size_x(&region->v2d.mask);
333  immRectf(pos,
334  t->tsnap.snapPoint[0] - pixelx,
335  region->v2d.cur.ymax,
336  t->tsnap.snapPoint[0] + pixelx,
337  region->v2d.cur.ymin);
340  }
341 }
342 
344 {
345  eRedrawFlag status = TREDRAW_NOTHING;
346 
347 #if 0 /* XXX need a proper selector for all snap mode */
348  if (BIF_snappingSupported(t->obedit) && (event->type == EVT_TABKEY) &&
349  (event->modifier & KM_SHIFT)) {
350  /* toggle snap and reinit */
351  t->settings->snap_flag ^= SCE_SNAP;
352  initSnapping(t, NULL);
353  status = TREDRAW_HARD;
354  }
355 #endif
356  if (event->type == MOUSEMOVE) {
357  status |= updateSelectedSnapPoint(t);
358  }
359 
360  return status;
361 }
362 
364 {
365  if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) {
366  return false;
367  }
368 
369  float iloc[3], loc[3], no[3];
370  float mval_fl[2];
371 
372  copy_v3_v3(iloc, td->loc);
373  if (tc->use_local_mat) {
374  mul_m4_v3(tc->mat, iloc);
375  }
376  else if (t->options & CTX_OBJECT) {
377  BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
378  copy_v3_v3(iloc, td->ob->obmat[3]);
379  }
380 
381  if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) !=
382  V3D_PROJ_RET_OK) {
383  return false;
384  }
385 
387  t->tsnap.object_context,
388  t->depsgraph,
389  t->region,
390  t->view,
392  &(const struct SnapObjectParams){
393  .snap_target_select = t->tsnap.target_select,
394  .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
395  .use_occlusion_test = false,
396  .use_backface_culling = t->tsnap.use_backface_culling,
397  },
398  NULL,
399  mval_fl,
400  NULL,
401  0,
402  loc,
403  no);
404  if (hit != SCE_SNAP_MODE_FACE_RAYCAST) {
405  return false;
406  }
407 
408  float tvec[3];
409  sub_v3_v3v3(tvec, loc, iloc);
410 
411  mul_m3_v3(td->smtx, tvec);
412 
413  add_v3_v3(td->loc, tvec);
414 
415  if (t->tsnap.align && (t->options & CTX_OBJECT)) {
416  /* handle alignment as well */
417  const float *original_normal;
418  float mat[3][3];
419 
420  /* In pose mode, we want to align normals with Y axis of bones. */
421  original_normal = td->axismtx[2];
422 
423  rotation_between_vecs_to_mat3(mat, original_normal, no);
424 
425  transform_data_ext_rotate(td, mat, true);
426 
427  /* TODO: support constraints for rotation too? see #ElementRotation. */
428  }
429  return true;
430 }
431 
433 {
434  if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST)) {
435  return;
436  }
437 
438  float init_loc[3];
439  float prev_loc[3];
440  float snap_loc[3], snap_no[3];
441 
442  copy_v3_v3(init_loc, td->iloc);
443  copy_v3_v3(prev_loc, td->loc);
444  if (tc->use_local_mat) {
445  mul_m4_v3(tc->mat, init_loc);
446  mul_m4_v3(tc->mat, prev_loc);
447  }
448  else if (t->options & CTX_OBJECT) {
449  BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
450  copy_v3_v3(init_loc, td->ob->obmat[3]);
451  }
452 
454  t->tsnap.object_context,
455  t->depsgraph,
456  t->region,
457  t->view,
459  &(const struct SnapObjectParams){
460  .snap_target_select = t->tsnap.target_select,
461  .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
462  .use_occlusion_test = false,
463  .use_backface_culling = false,
464  .face_nearest_steps = t->tsnap.face_nearest_steps,
465  .keep_on_same_target = t->tsnap.flag & SCE_SNAP_KEEP_ON_SAME_OBJECT,
466  },
467  init_loc,
468  NULL,
469  prev_loc,
470  0,
471  snap_loc,
472  snap_no);
473 
474  if (hit != SCE_SNAP_MODE_FACE_NEAREST) {
475  return;
476  }
477 
478  float tvec[3];
479  sub_v3_v3v3(tvec, snap_loc, prev_loc);
480  mul_m3_v3(td->smtx, tvec);
481  add_v3_v3(td->loc, tvec);
482 
483  /* TODO: support snap alignment similar to #SCE_SNAP_MODE_FACE_RAYCAST? */
484 }
485 
487 {
489  return;
490  }
491 
492  /* XXX FLICKER IN OBJECT MODE */
494  TransData *td = tc->data;
495  for (int i = 0; i < tc->data_len; i++, td++) {
496  if (td->flag & TD_SKIP) {
497  continue;
498  }
499 
500  if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
501  continue;
502  }
503 
504  /* If both face ray-cast and face nearest methods are enabled, start with face ray-cast and
505  * fallback to face nearest ray-cast does not hit. */
506  bool hit = applyFaceProject(t, tc, td);
507  if (!hit) {
508  applyFaceNearest(t, tc, td);
509  }
510 #if 0 /* TODO: support this? */
511  constraintTransLim(t, td);
512 #endif
513  }
514  }
515 }
516 
518 {
519  int i;
520 
521  if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
522  return;
523  }
524 
525  float grid_size = (t->modifiers & MOD_PRECISION) ? t->snap_spatial[1] : t->snap_spatial[0];
526 
527  /* early exit on unusable grid size */
528  if (grid_size == 0.0f) {
529  return;
530  }
531 
533  TransData *td;
534 
535  for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
536  float iloc[3], loc[3], tvec[3];
537  if (td->flag & TD_SKIP) {
538  continue;
539  }
540 
541  if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
542  continue;
543  }
544 
545  copy_v3_v3(iloc, td->loc);
546  if (tc->use_local_mat) {
547  mul_m4_v3(tc->mat, iloc);
548  }
549  else if (t->options & CTX_OBJECT) {
550  BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
551  copy_v3_v3(iloc, td->ob->obmat[3]);
552  }
553 
554  mul_v3_v3fl(loc, iloc, 1.0f / grid_size);
555  loc[0] = roundf(loc[0]);
556  loc[1] = roundf(loc[1]);
557  loc[2] = roundf(loc[2]);
558  mul_v3_fl(loc, grid_size);
559 
560  sub_v3_v3v3(tvec, loc, iloc);
561  mul_m3_v3(td->smtx, tvec);
562  add_v3_v3(td->loc, tvec);
563  }
564  }
565 }
566 
567 void applySnappingAsGroup(TransInfo *t, float *vec)
568 {
570  return;
571  }
572 
573  if (t->tsnap.status & SNAP_FORCED) {
574  t->tsnap.targetSnap(t);
575 
576  t->tsnap.applySnap(t, vec);
577  }
578  else if (((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) != 0) &&
579  activeSnap(t)) {
580  double current = PIL_check_seconds_timer();
581 
582  /* Time base quirky code to go around find-nearest slowness. */
583  /* TODO: add exception for object mode, no need to slow it down then. */
584  if (current - t->tsnap.last >= 0.01) {
585  if (t->tsnap.calcSnap) {
586  t->tsnap.calcSnap(t, vec);
587  }
588  if (t->tsnap.targetSnap) {
589  t->tsnap.targetSnap(t);
590  }
591 
592  t->tsnap.last = current;
593  }
594 
595  if (validSnap(t)) {
596  t->tsnap.applySnap(t, vec);
597  }
598  }
599 }
600 
602 {
603  t->tsnap.status = SNAP_RESETTED;
604  t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
605  t->tsnap.align = false;
606  t->tsnap.project = false;
607  t->tsnap.mode = SCE_SNAP_MODE_NONE;
608  t->tsnap.target_select = SCE_SNAP_TARGET_ALL;
609  t->tsnap.source_select = SCE_SNAP_SOURCE_CLOSEST;
610  t->tsnap.last = 0;
611 
612  t->tsnap.snapNormal[0] = 0;
613  t->tsnap.snapNormal[1] = 0;
614  t->tsnap.snapNormal[2] = 0;
615 
616  t->tsnap.snapNodeBorder = 0;
617 }
618 
620 {
621  return t->tsnap.align;
622 }
623 
625 {
626  if (validSnap(t)) {
627  if (!is_zero_v3(t->tsnap.snapNormal)) {
628  return true;
629  }
630  }
631 
632  return false;
633 }
634 
636 {
639  return false;
640  }
641 
642  return true;
643 }
644 
646 {
648  return false;
649  }
650 
651  BMLoop *l_iter, *l_first;
652  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
653  do {
654  if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
655  return false;
656  }
657  } while ((l_iter = l_iter->next) != l_first);
658 
659  return true;
660 }
661 
663 {
664  ToolSettings *ts = t->settings;
665  if (t->spacetype == SPACE_NODE) {
666  return ts->snap_flag_node;
667  }
668  if (t->spacetype == SPACE_IMAGE) {
669  return ts->snap_uv_flag;
670  }
671  if (t->spacetype == SPACE_SEQ) {
672  return ts->snap_flag_seq;
673  }
674  return ts->snap_flag;
675 }
676 
678 {
679  ToolSettings *ts = t->settings;
680 
681  if (t->spacetype == SPACE_NODE) {
682  return ts->snap_node_mode;
683  }
684 
685  if (t->spacetype == SPACE_IMAGE) {
686  eSnapMode snap_mode = ts->snap_uv_mode;
687  if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) &&
688  (t->mode == TFM_TRANSLATION)) {
689  snap_mode &= ~SCE_SNAP_MODE_INCREMENT;
690  snap_mode |= SCE_SNAP_MODE_GRID;
691  }
692  return snap_mode;
693  }
694 
695  if (t->spacetype == SPACE_SEQ) {
696  return SEQ_tool_settings_snap_mode_get(t->scene);
697  }
698 
699  if (t->spacetype == SPACE_VIEW3D) {
700  if (t->options & (CTX_CAMERA | CTX_EDGE_DATA | CTX_PAINT_CURVE)) {
702  }
703 
704  eSnapMode snap_mode = ts->snap_mode;
705  if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) &&
706  (t->mode == TFM_TRANSLATION)) {
707  /* Special case in which snap to increments is transformed to snap to grid. */
708  snap_mode &= ~SCE_SNAP_MODE_INCREMENT;
709  snap_mode |= SCE_SNAP_MODE_GRID;
710  }
711  return snap_mode;
712  }
713 
714  if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
715  /* No incremental snapping. */
716  return 0;
717  }
718 
720 }
721 
723 {
724  ViewLayer *view_layer = t->view_layer;
725  Base *base_act = view_layer->basact;
726 
728 
729  /* `t->tsnap.target_select` not initialized yet. */
730  BLI_assert(t->tsnap.target_select == SCE_SNAP_TARGET_ALL);
731 
732  if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) {
733  if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
734  /* Particles edit mode. */
735  return ret;
736  }
737 
739  /* In "Edit Strokes" mode,
740  * snap tool can perform snap to selected or active objects (see T49632)
741  * TODO: perform self snap in gpencil_strokes.
742  *
743  * When we're moving the origins, allow snapping onto our own geometry (see T69132). */
744  return ret;
745  }
746 
747  const int obedit_type = t->obedit_type;
748  if (obedit_type != -1) {
749  /* Edit mode */
750  if (obedit_type == OB_MESH) {
751  /* Editing a mesh */
752  if ((t->flag & T_PROP_EDIT) != 0) {
753  /* Exclude editmesh when using proportional edit */
755  }
756  }
757  else if (ELEM(obedit_type, OB_ARMATURE, OB_CURVES_LEGACY, OB_SURF, OB_LATTICE, OB_MBALL)) {
758  /* Temporary limited to edit mode armature, curves, surfaces, lattices, and metaballs. */
760  }
761  }
762  else {
763  /* Object or pose mode. */
765  }
766  }
767  else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
769  }
770 
771  return ret;
772 }
773 
775 {
776  if ((t->spacetype != SPACE_VIEW3D) || !(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) {
777  /* Force project off when not supported. */
778  t->tsnap.project = false;
779  }
780 
781  if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) {
782  /* Not with camera selected in camera view. */
783  if (!(t->options & CTX_CAMERA)) {
785  }
786  }
787 
788  if (t->spacetype == SPACE_VIEW3D) {
789  if (t->tsnap.object_context == NULL) {
790  t->tsnap.use_backface_culling = snap_use_backface_culling(t);
791  t->tsnap.object_context = ED_transform_snap_object_context_create(t->scene, 0);
792 
793  if (t->data_type == &TransConvertType_Mesh) {
794  /* Ignore elements being transformed. */
796  t->tsnap.object_context,
801  }
802  else {
803  /* Ignore hidden geometry in the general case. */
805  t->tsnap.object_context,
807  (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled,
808  (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled,
810  }
811  }
812  }
813  else if (t->spacetype == SPACE_SEQ) {
814  if (t->tsnap.seq_context == NULL) {
815  t->tsnap.seq_context = transform_snap_sequencer_data_alloc(t);
816  }
817  }
818 }
819 
821 {
822  ToolSettings *ts = t->settings;
823  eSnapSourceSelect snap_source = ts->snap_target;
824 
825  resetSnapping(t);
826  t->tsnap.mode = snap_mode_from_spacetype(t);
827  t->tsnap.flag = snap_flag_from_spacetype(t);
828  t->tsnap.target_select = snap_target_select_from_spacetype(t);
829  t->tsnap.face_nearest_steps = max_ii(ts->snap_face_nearest_steps, 1);
830 
831  /* if snap property exists */
832  PropertyRNA *prop;
833  if (op && (prop = RNA_struct_find_property(op->ptr, "snap")) &&
834  RNA_property_is_set(op->ptr, prop)) {
835  if (RNA_property_boolean_get(op->ptr, prop)) {
836  t->modifiers |= MOD_SNAP;
837 
838  if ((prop = RNA_struct_find_property(op->ptr, "snap_elements")) &&
839  RNA_property_is_set(op->ptr, prop)) {
840  t->tsnap.mode = RNA_property_enum_get(op->ptr, prop);
841  }
842 
843  /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
844  * "target" (now, "source" is geometry to be moved and "target" is geometry to which moved
845  * geometry is snapped). */
846  if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) &&
847  RNA_property_is_set(op->ptr, prop)) {
848  snap_source = RNA_property_enum_get(op->ptr, prop);
849  }
850 
851  if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) &&
852  RNA_property_is_set(op->ptr, prop)) {
853  RNA_property_float_get_array(op->ptr, prop, t->tsnap.snapPoint);
854  t->tsnap.status |= SNAP_FORCED | POINT_INIT;
855  }
856 
857  /* snap align only defined in specific cases */
858  if ((prop = RNA_struct_find_property(op->ptr, "snap_align")) &&
859  RNA_property_is_set(op->ptr, prop)) {
860  t->tsnap.align = RNA_property_boolean_get(op->ptr, prop);
861  RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
862  normalize_v3(t->tsnap.snapNormal);
863  }
864 
865  if ((prop = RNA_struct_find_property(op->ptr, "use_snap_project")) &&
866  RNA_property_is_set(op->ptr, prop)) {
867  t->tsnap.project = RNA_property_boolean_get(op->ptr, prop);
868  }
869 
870  /* use_snap_self is misnamed and should be use_snap_active */
871  if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) &&
872  RNA_property_is_set(op->ptr, prop)) {
873  SET_FLAG_FROM_TEST(t->tsnap.target_select,
874  !RNA_property_boolean_get(op->ptr, prop),
876  }
877 
878  if ((prop = RNA_struct_find_property(op->ptr, "use_snap_edit")) &&
879  RNA_property_is_set(op->ptr, prop)) {
880  SET_FLAG_FROM_TEST(t->tsnap.target_select,
881  !RNA_property_boolean_get(op->ptr, prop),
883  }
884 
885  if ((prop = RNA_struct_find_property(op->ptr, "use_snap_nonedit")) &&
886  RNA_property_is_set(op->ptr, prop)) {
887  SET_FLAG_FROM_TEST(t->tsnap.target_select,
888  !RNA_property_boolean_get(op->ptr, prop),
890  }
891 
892  if ((prop = RNA_struct_find_property(op->ptr, "use_snap_selectable")) &&
893  RNA_property_is_set(op->ptr, prop)) {
894  SET_FLAG_FROM_TEST(t->tsnap.target_select,
895  RNA_property_boolean_get(op->ptr, prop),
897  }
898  }
899  }
900  /* use scene defaults only when transform is modal */
901  else if (t->flag & T_MODAL) {
902  if (transformModeUseSnap(t) && (t->tsnap.flag & SCE_SNAP)) {
903  t->modifiers |= MOD_SNAP;
904  }
905 
906  t->tsnap.align = ((t->tsnap.flag & SCE_SNAP_ROTATE) != 0);
907  t->tsnap.project = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
908  t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
909  SET_FLAG_FROM_TEST(t->tsnap.target_select,
912  SET_FLAG_FROM_TEST(t->tsnap.target_select,
915  SET_FLAG_FROM_TEST(t->tsnap.target_select,
918  SET_FLAG_FROM_TEST(t->tsnap.target_select,
921  }
922 
923  t->tsnap.source_select = snap_source;
924 
926 }
927 
929 {
930  if ((t->spacetype == SPACE_SEQ) && t->tsnap.seq_context) {
931  transform_snap_sequencer_data_free(t->tsnap.seq_context);
932  t->tsnap.seq_context = NULL;
933  }
934  else if (t->tsnap.object_context) {
935  ED_transform_snap_object_context_destroy(t->tsnap.object_context);
936  t->tsnap.object_context = NULL;
937  }
938 }
939 
941 {
942  if (t->spacetype == SPACE_VIEW3D) {
943  t->tsnap.calcSnap = snap_calc_view3d_fn;
944  }
945  else if (t->spacetype == SPACE_IMAGE) {
946  SpaceImage *sima = t->area->spacedata.first;
947  Object *obact = t->view_layer->basact ? t->view_layer->basact->object : NULL;
948 
949  const bool is_uv_editor = sima->mode == SI_MODE_UV;
950  const bool has_edit_object = obact && BKE_object_is_in_editmode(obact);
951  if (is_uv_editor && has_edit_object) {
952  t->tsnap.calcSnap = snap_calc_uv_fn;
953  }
954  }
955  else if (t->spacetype == SPACE_NODE) {
956  t->tsnap.calcSnap = snap_calc_node_fn;
957  }
958  else if (t->spacetype == SPACE_SEQ) {
959  t->tsnap.calcSnap = snap_calc_sequencer_fn;
960  /* The target is calculated along with the snap point. */
961  return;
962  }
963 
964  switch (t->tsnap.source_select) {
966  t->tsnap.targetSnap = TargetSnapClosest;
967  break;
969  if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
970  t->tsnap.targetSnap = TargetSnapCenter;
971  break;
972  }
973  /* Can't do TARGET_CENTER with these modes,
974  * use TARGET_MEDIAN instead. */
977  t->tsnap.targetSnap = TargetSnapMedian;
978  break;
980  t->tsnap.targetSnap = TargetSnapActive;
981  break;
982  }
983 }
984 
986 {
987  /* Currently only 3D viewport works for snapping points. */
988  if (t->tsnap.status & POINT_INIT && t->spacetype == SPACE_VIEW3D) {
989  TransSnapPoint *p = MEM_callocN(sizeof(TransSnapPoint), "SnapPoint");
990 
991  t->tsnap.selectedPoint = p;
992 
993  copy_v3_v3(p->co, t->tsnap.snapPoint);
994 
995  BLI_addtail(&t->tsnap.points, p);
996 
997  t->tsnap.status |= MULTI_POINTS;
998  }
999 }
1000 
1002 {
1003  eRedrawFlag status = TREDRAW_NOTHING;
1004 
1005  if (t->tsnap.status & MULTI_POINTS) {
1006  TransSnapPoint *p, *closest_p = NULL;
1007  float dist_min_sq = TRANSFORM_SNAP_MAX_PX;
1008  const float mval_fl[2] = {t->mval[0], t->mval[1]};
1009  float screen_loc[2];
1010 
1011  for (p = t->tsnap.points.first; p; p = p->next) {
1012  float dist_sq;
1013 
1014  if (ED_view3d_project_float_global(t->region, p->co, screen_loc, V3D_PROJ_TEST_NOP) !=
1015  V3D_PROJ_RET_OK) {
1016  continue;
1017  }
1018 
1019  dist_sq = len_squared_v2v2(mval_fl, screen_loc);
1020 
1021  if (dist_sq < dist_min_sq) {
1022  closest_p = p;
1023  dist_min_sq = dist_sq;
1024  }
1025  }
1026 
1027  if (closest_p) {
1028  if (t->tsnap.selectedPoint != closest_p) {
1029  status = TREDRAW_HARD;
1030  }
1031 
1032  t->tsnap.selectedPoint = closest_p;
1033  }
1034  }
1035 
1036  return status;
1037 }
1038 
1040 {
1041  if (t->tsnap.status & MULTI_POINTS) {
1043 
1044  if (t->tsnap.selectedPoint) {
1045  BLI_freelinkN(&t->tsnap.points, t->tsnap.selectedPoint);
1046 
1047  if (BLI_listbase_is_empty(&t->tsnap.points)) {
1048  t->tsnap.status &= ~MULTI_POINTS;
1049  }
1050 
1051  t->tsnap.selectedPoint = NULL;
1052  }
1053  }
1054 }
1055 
1056 void getSnapPoint(const TransInfo *t, float vec[3])
1057 {
1058  if (t->tsnap.points.first) {
1059  TransSnapPoint *p;
1060  int total = 0;
1061 
1062  vec[0] = vec[1] = vec[2] = 0;
1063 
1064  for (p = t->tsnap.points.first; p; p = p->next, total++) {
1065  add_v3_v3(vec, p->co);
1066  }
1067 
1068  if (t->tsnap.status & POINT_INIT) {
1069  add_v3_v3(vec, t->tsnap.snapPoint);
1070  total++;
1071  }
1072 
1073  mul_v3_fl(vec, 1.0f / total);
1074  }
1075  else {
1076  copy_v3_v3(vec, t->tsnap.snapPoint);
1077  }
1078 }
1079 
1082 /* -------------------------------------------------------------------- */
1086 static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
1087 {
1088  BLI_assert(t->spacetype == SPACE_VIEW3D);
1089  float loc[3];
1090  float no[3];
1091  float mval[2];
1092  bool found = false;
1093  eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
1094  float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */
1095 
1096  mval[0] = t->mval[0];
1097  mval[1] = t->mval[1];
1098 
1099  if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) {
1100  zero_v3(no); /* objects won't set this */
1101  snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no);
1102  found = (snap_elem != SCE_SNAP_MODE_NONE);
1103  }
1104  if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
1105  bool use_peel = (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0;
1106  found = peelObjectsTransform(t, mval, use_peel, loc, no, NULL);
1107 
1108  if (found) {
1109  snap_elem = SCE_SNAP_MODE_VOLUME;
1110  }
1111  }
1112 
1113  if (found == true) {
1114  copy_v3_v3(t->tsnap.snapPoint, loc);
1115  copy_v3_v3(t->tsnap.snapNormal, no);
1116 
1117  t->tsnap.status |= POINT_INIT;
1118  }
1119  else {
1120  t->tsnap.status &= ~POINT_INIT;
1121  }
1122 
1123  t->tsnap.snapElem = snap_elem;
1124 }
1125 
1126 static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
1127 {
1128  BLI_assert(t->spacetype == SPACE_IMAGE);
1129  if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
1130  uint objects_len = 0;
1132  t->view_layer, NULL, &objects_len);
1133 
1134  float dist_sq = square_f((float)SNAP_MIN_DISTANCE);
1135  if (ED_uvedit_nearest_uv_multi(&t->region->v2d,
1136  t->scene,
1137  objects,
1138  objects_len,
1139  t->mval,
1140  t->tsnap.target_select & SCE_SNAP_TARGET_NOT_SELECTED,
1141  &dist_sq,
1142  t->tsnap.snapPoint)) {
1143  t->tsnap.snapPoint[0] *= t->aspect[0];
1144  t->tsnap.snapPoint[1] *= t->aspect[1];
1145 
1146  t->tsnap.status |= POINT_INIT;
1147  }
1148  else {
1149  t->tsnap.status &= ~POINT_INIT;
1150  }
1151  MEM_freeN(objects);
1152  }
1153 }
1154 
1155 static void snap_calc_node_fn(TransInfo *t, float *UNUSED(vec))
1156 {
1157  BLI_assert(t->spacetype == SPACE_NODE);
1158  if (t->tsnap.mode & (SCE_SNAP_MODE_NODE_X | SCE_SNAP_MODE_NODE_Y)) {
1159  float loc[2];
1160  float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */
1161  char node_border;
1162 
1163  if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) {
1164  copy_v2_v2(t->tsnap.snapPoint, loc);
1165  t->tsnap.snapNodeBorder = node_border;
1166 
1167  t->tsnap.status |= POINT_INIT;
1168  }
1169  else {
1170  t->tsnap.status &= ~POINT_INIT;
1171  }
1172  }
1173 }
1174 
1175 static void snap_calc_sequencer_fn(TransInfo *t, float *UNUSED(vec))
1176 {
1177  BLI_assert(t->spacetype == SPACE_SEQ);
1179  t->tsnap.status |= (POINT_INIT | TARGET_INIT);
1180  }
1181  else {
1182  t->tsnap.status &= ~(POINT_INIT | TARGET_INIT);
1183  }
1184 }
1185 
1188 /* -------------------------------------------------------------------- */
1192 static void snap_target_median_impl(TransInfo *t, float r_median[3])
1193 {
1194  int i_accum = 0;
1195 
1196  zero_v3(r_median);
1197 
1199  TransData *td = tc->data;
1200  int i;
1201  float v[3];
1202  zero_v3(v);
1203 
1204  for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
1205  add_v3_v3(v, td->center);
1206  }
1207 
1208  if (i == 0) {
1209  /* Is this possible? */
1210  continue;
1211  }
1212 
1213  mul_v3_fl(v, 1.0 / i);
1214 
1215  if (tc->use_local_mat) {
1216  mul_m4_v3(tc->mat, v);
1217  }
1218 
1219  add_v3_v3(r_median, v);
1220  i_accum++;
1221  }
1222 
1223  mul_v3_fl(r_median, 1.0 / i_accum);
1224 
1225  // TargetSnapOffset(t, NULL);
1226 }
1227 
1229 {
1230  /* Only need to calculate once. */
1231  if ((t->tsnap.status & TARGET_GRID_INIT) == 0) {
1232  if (t->data_type == &TransConvertType_Cursor3D) {
1233  /* Use a fallback when transforming the cursor.
1234  * In this case the center is _not_ derived from the cursor which is being transformed. */
1235  copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc);
1236  }
1237  else if (t->around == V3D_AROUND_CURSOR) {
1238  /* Use a fallback for cursor selection,
1239  * this isn't useful as a global center for absolute grid snapping
1240  * since its not based on the position of the selection. */
1241  snap_target_median_impl(t, t->tsnap.snapTargetGrid);
1242  }
1243  else {
1244  copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global);
1245  }
1246  t->tsnap.status |= TARGET_GRID_INIT;
1247  }
1248 }
1249 
1251 {
1252  if (t->spacetype == SPACE_NODE && td != NULL) {
1253  bNode *node = td->extra;
1254  char border = t->tsnap.snapNodeBorder;
1255  float width = BLI_rctf_size_x(&node->totr);
1256  float height = BLI_rctf_size_y(&node->totr);
1257 
1258 #ifdef USE_NODE_CENTER
1259  if (border & NODE_LEFT) {
1260  t->tsnap.snapTarget[0] -= 0.5f * width;
1261  }
1262  if (border & NODE_RIGHT) {
1263  t->tsnap.snapTarget[0] += 0.5f * width;
1264  }
1265  if (border & NODE_BOTTOM) {
1266  t->tsnap.snapTarget[1] -= 0.5f * height;
1267  }
1268  if (border & NODE_TOP) {
1269  t->tsnap.snapTarget[1] += 0.5f * height;
1270  }
1271 #else
1272  if (border & NODE_LEFT) {
1273  t->tsnap.snapTarget[0] -= 0.0f;
1274  }
1275  if (border & NODE_RIGHT) {
1276  t->tsnap.snapTarget[0] += width;
1277  }
1278  if (border & NODE_BOTTOM) {
1279  t->tsnap.snapTarget[1] -= height;
1280  }
1281  if (border & NODE_TOP) {
1282  t->tsnap.snapTarget[1] += 0.0f;
1283  }
1284 #endif
1285  }
1286 }
1287 
1289 {
1290  /* Only need to calculate once */
1291  if ((t->tsnap.status & TARGET_INIT) == 0) {
1292  copy_v3_v3(t->tsnap.snapTarget, t->center_global);
1294 
1295  t->tsnap.status |= TARGET_INIT;
1296  }
1297 }
1298 
1300 {
1301  /* Only need to calculate once */
1302  if ((t->tsnap.status & TARGET_INIT) == 0) {
1303  if (calculateCenterActive(t, true, t->tsnap.snapTarget)) {
1305 
1306  t->tsnap.status |= TARGET_INIT;
1307  }
1308  /* No active, default to median */
1309  else {
1310  t->tsnap.source_select = SCE_SNAP_SOURCE_MEDIAN;
1311  t->tsnap.targetSnap = TargetSnapMedian;
1313  }
1314  }
1315 }
1316 
1318 {
1319  /* Only need to calculate once. */
1320  if ((t->tsnap.status & TARGET_INIT) == 0) {
1321  snap_target_median_impl(t, t->tsnap.snapTarget);
1322  t->tsnap.status |= TARGET_INIT;
1323  }
1324 }
1325 
1327 {
1328  /* Only valid if a snap point has been selected. */
1329  if (t->tsnap.status & POINT_INIT) {
1330  float dist_closest = 0.0f;
1331  TransData *closest = NULL;
1332 
1333  /* Object mode */
1334  if (t->options & CTX_OBJECT) {
1335  int i;
1337  TransData *td;
1338  for (td = tc->data, i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
1339  const BoundBox *bb = NULL;
1340 
1341  if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
1342  bb = BKE_object_boundbox_get(td->ob);
1343  }
1344 
1345  /* use boundbox if possible */
1346  if (bb) {
1347  int j;
1348 
1349  for (j = 0; j < 8; j++) {
1350  float loc[3];
1351  float dist;
1352 
1353  copy_v3_v3(loc, bb->vec[j]);
1354  mul_m4_v3(td->ext->obmat, loc);
1355 
1356  dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
1357 
1358  if ((dist != TRANSFORM_DIST_INVALID) &&
1359  (closest == NULL || fabsf(dist) < fabsf(dist_closest))) {
1360  copy_v3_v3(t->tsnap.snapTarget, loc);
1361  closest = td;
1362  dist_closest = dist;
1363  }
1364  }
1365  }
1366  /* use element center otherwise */
1367  else {
1368  float loc[3];
1369  float dist;
1370 
1371  copy_v3_v3(loc, td->center);
1372 
1373  dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
1374 
1375  if ((dist != TRANSFORM_DIST_INVALID) &&
1376  (closest == NULL || fabsf(dist) < fabsf(dist_closest))) {
1377  copy_v3_v3(t->tsnap.snapTarget, loc);
1378  closest = td;
1379  }
1380  }
1381  }
1382  }
1383  }
1384  else {
1386  TransData *td = tc->data;
1387  int i;
1388  for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
1389  float loc[3];
1390  float dist;
1391 
1392  copy_v3_v3(loc, td->center);
1393 
1394  if (tc->use_local_mat) {
1395  mul_m4_v3(tc->mat, loc);
1396  }
1397 
1398  dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
1399 
1400  if ((dist != TRANSFORM_DIST_INVALID) &&
1401  (closest == NULL || fabsf(dist) < fabsf(dist_closest))) {
1402  copy_v3_v3(t->tsnap.snapTarget, loc);
1403  closest = td;
1404  dist_closest = dist;
1405  }
1406  }
1407  }
1408  }
1409 
1411 
1412  t->tsnap.status |= TARGET_INIT;
1413  }
1414 }
1415 
1418 /* -------------------------------------------------------------------- */
1423  TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3])
1424 {
1425  float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global;
1427  t->tsnap.object_context,
1428  t->depsgraph,
1429  t->region,
1430  t->view,
1431  t->tsnap.mode,
1432  &(const struct SnapObjectParams){
1433  .snap_target_select = t->tsnap.target_select,
1434  .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
1435  .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE_RAYCAST,
1436  .use_backface_culling = t->tsnap.use_backface_culling,
1437  },
1438  NULL,
1439  mval,
1440  target,
1441  dist_px,
1442  r_loc,
1443  r_no);
1444 }
1445 
1448 /* -------------------------------------------------------------------- */
1453  const float mval[2],
1454  const bool use_peel_object,
1455  /* return args */
1456  float r_loc[3],
1457  float r_no[3],
1458  float *r_thickness)
1459 {
1460  ListBase depths_peel = {0};
1462  t->tsnap.object_context,
1463  t->depsgraph,
1464  t->region,
1465  t->view,
1466  &(const struct SnapObjectParams){
1467  .snap_target_select = t->tsnap.target_select,
1468  .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
1469  },
1470  mval,
1471  -1.0f,
1472  false,
1473  &depths_peel);
1474 
1475  if (!BLI_listbase_is_empty(&depths_peel)) {
1476  /* At the moment we only use the hits of the first object */
1477  struct SnapObjectHitDepth *hit_min = depths_peel.first;
1478  for (struct SnapObjectHitDepth *iter = hit_min->next; iter; iter = iter->next) {
1479  if (iter->depth < hit_min->depth) {
1480  hit_min = iter;
1481  }
1482  }
1483  struct SnapObjectHitDepth *hit_max = NULL;
1484 
1485  if (use_peel_object) {
1486  /* if peeling objects, take the first and last from each object */
1487  hit_max = hit_min;
1488  for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) {
1489  if ((iter->depth > hit_max->depth) && (iter->ob_uuid == hit_min->ob_uuid)) {
1490  hit_max = iter;
1491  }
1492  }
1493  }
1494  else {
1495  /* otherwise, pair first with second and so on */
1496  for (struct SnapObjectHitDepth *iter = depths_peel.first; iter; iter = iter->next) {
1497  if ((iter != hit_min) && (iter->ob_uuid == hit_min->ob_uuid)) {
1498  if (hit_max == NULL) {
1499  hit_max = iter;
1500  }
1501  else if (iter->depth < hit_max->depth) {
1502  hit_max = iter;
1503  }
1504  }
1505  }
1506  /* In this case has only one hit. treat as ray-cast. */
1507  if (hit_max == NULL) {
1508  hit_max = hit_min;
1509  }
1510  }
1511 
1512  mid_v3_v3v3(r_loc, hit_min->co, hit_max->co);
1513 
1514  if (r_thickness) {
1515  *r_thickness = hit_max->depth - hit_min->depth;
1516  }
1517 
1518  /* XXX, is there a correct normal in this case ???, for now just z up */
1519  r_no[0] = 0.0;
1520  r_no[1] = 0.0;
1521  r_no[2] = 1.0;
1522 
1523  BLI_freelistN(&depths_peel);
1524  return true;
1525  }
1526  return false;
1527 }
1528 
1531 /* -------------------------------------------------------------------- */
1535 static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select)
1536 {
1537  /* node is use for snapping only if a) snap mode matches and b) node is inside the view */
1538  return (((snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED) && !(node->flag & NODE_SELECT)) ||
1539  (snap_target_select == SCE_SNAP_TARGET_ALL && !(node->flag & NODE_ACTIVE))) &&
1540  (node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin &&
1541  node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin);
1542 }
1543 
1544 static NodeBorder snapNodeBorder(eSnapMode snap_node_mode)
1545 {
1546  NodeBorder flag = 0;
1547  if (snap_node_mode & SCE_SNAP_MODE_NODE_X) {
1548  flag |= NODE_LEFT | NODE_RIGHT;
1549  }
1550  if (snap_node_mode & SCE_SNAP_MODE_NODE_Y) {
1551  flag |= NODE_TOP | NODE_BOTTOM;
1552  }
1553  return flag;
1554 }
1555 
1556 static bool snapNode(ToolSettings *ts,
1557  SpaceNode *UNUSED(snode),
1558  ARegion *region,
1559  bNode *node,
1560  const int mval[2],
1561  float r_loc[2],
1562  float *r_dist_px,
1563  char *r_node_border)
1564 {
1565  View2D *v2d = &region->v2d;
1567  bool retval = false;
1568  rcti totr;
1569  int new_dist;
1570 
1571  UI_view2d_view_to_region_rcti(v2d, &node->totr, &totr);
1572 
1573  if (border & NODE_LEFT) {
1574  new_dist = abs(totr.xmin - mval[0]);
1575  if (new_dist < *r_dist_px) {
1576  UI_view2d_region_to_view(v2d, totr.xmin, mval[1], &r_loc[0], &r_loc[1]);
1577  *r_dist_px = new_dist;
1578  *r_node_border = NODE_LEFT;
1579  retval = true;
1580  }
1581  }
1582 
1583  if (border & NODE_RIGHT) {
1584  new_dist = abs(totr.xmax - mval[0]);
1585  if (new_dist < *r_dist_px) {
1586  UI_view2d_region_to_view(v2d, totr.xmax, mval[1], &r_loc[0], &r_loc[1]);
1587  *r_dist_px = new_dist;
1588  *r_node_border = NODE_RIGHT;
1589  retval = true;
1590  }
1591  }
1592 
1593  if (border & NODE_BOTTOM) {
1594  new_dist = abs(totr.ymin - mval[1]);
1595  if (new_dist < *r_dist_px) {
1596  UI_view2d_region_to_view(v2d, mval[0], totr.ymin, &r_loc[0], &r_loc[1]);
1597  *r_dist_px = new_dist;
1598  *r_node_border = NODE_BOTTOM;
1599  retval = true;
1600  }
1601  }
1602 
1603  if (border & NODE_TOP) {
1604  new_dist = abs(totr.ymax - mval[1]);
1605  if (new_dist < *r_dist_px) {
1606  UI_view2d_region_to_view(v2d, mval[0], totr.ymax, &r_loc[0], &r_loc[1]);
1607  *r_dist_px = new_dist;
1608  *r_node_border = NODE_TOP;
1609  retval = true;
1610  }
1611  }
1612 
1613  return retval;
1614 }
1615 
1616 static bool snapNodes(ToolSettings *ts,
1617  SpaceNode *snode,
1618  ARegion *region,
1619  const int mval[2],
1620  eSnapTargetSelect snap_target_select,
1621  float r_loc[2],
1622  float *r_dist_px,
1623  char *r_node_border)
1624 {
1625  bNodeTree *ntree = snode->edittree;
1626  bNode *node;
1627  bool retval = false;
1628 
1629  *r_node_border = 0;
1630 
1631  for (node = ntree->nodes.first; node; node = node->next) {
1632  if (snapNodeTest(&region->v2d, node, snap_target_select)) {
1633  retval |= snapNode(ts, snode, region, node, mval, r_loc, r_dist_px, r_node_border);
1634  }
1635  }
1636 
1637  return retval;
1638 }
1639 
1641  TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border)
1642 {
1643  return snapNodes(t->settings,
1644  t->area->spacedata.first,
1645  t->region,
1646  mval,
1647  t->tsnap.target_select,
1648  r_loc,
1649  r_dist_px,
1650  r_node_border);
1651 }
1652 
1655 /* -------------------------------------------------------------------- */
1659 static void snap_grid_apply(
1660  TransInfo *t, const int max_index, const float grid_dist, const float loc[3], float r_out[3])
1661 {
1662  BLI_assert(max_index <= 2);
1664  const float *center_global = t->tsnap.snapTargetGrid;
1665  const float *asp = t->aspect;
1666 
1667  float in[3];
1668  if (t->con.mode & CON_APPLY) {
1669  BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE);
1670  t->con.applyVec(t, NULL, NULL, loc, in);
1671  }
1672  else {
1673  copy_v3_v3(in, loc);
1674  }
1675 
1676  for (int i = 0; i <= max_index; i++) {
1677  const float iter_fac = grid_dist * asp[i];
1678  r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i];
1679  }
1680 }
1681 
1682 bool transform_snap_grid(TransInfo *t, float *val)
1683 {
1684  if (!activeSnap(t)) {
1685  return false;
1686  }
1687 
1688  if ((!(t->tsnap.mode & SCE_SNAP_MODE_GRID)) || validSnap(t)) {
1689  /* Don't do grid snapping if there is a valid snap point. */
1690  return false;
1691  }
1692 
1693  /* Don't do grid snapping if not in 3D viewport or UV editor */
1694  if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
1695  return false;
1696  }
1697 
1698  if (t->mode != TFM_TRANSLATION) {
1699  return false;
1700  }
1701 
1702  float grid_dist = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
1703 
1704  /* Early bailing out if no need to snap */
1705  if (grid_dist == 0.0f) {
1706  return false;
1707  }
1708 
1709  snap_grid_apply(t, t->idx_max, grid_dist, val, val);
1710  t->tsnap.snapElem = SCE_SNAP_MODE_GRID;
1711  return true;
1712 }
1713 
1715  const int max_index,
1716  const float increment_val,
1717  const float aspect[3],
1718  const float loc[3],
1719  float r_out[3])
1720 {
1721  /* relative snapping in fixed increments */
1722  for (int i = 0; i <= max_index; i++) {
1723  const float iter_fac = increment_val * aspect[i];
1724  r_out[i] = iter_fac * roundf(loc[i] / iter_fac);
1725  }
1726 }
1727 
1728 static void snap_increment_apply(const TransInfo *t,
1729  const int max_index,
1730  const float increment_dist,
1731  float *r_val)
1732 {
1734  BLI_assert(max_index <= 2);
1735 
1736  /* Early bailing out if no need to snap */
1737  if (increment_dist == 0.0f) {
1738  return;
1739  }
1740 
1741  float asp_local[3] = {1, 1, 1};
1742  const bool use_aspect = ELEM(t->mode, TFM_TRANSLATION);
1743  const float *asp = use_aspect ? t->aspect : asp_local;
1744 
1745  if (use_aspect) {
1746  /* custom aspect for fcurve */
1747  if (t->spacetype == SPACE_GRAPH) {
1748  View2D *v2d = &t->region->v2d;
1749  Scene *scene = t->scene;
1750  SpaceGraph *sipo = t->area->spacedata.first;
1752  v2d, scene, sipo->flag & SIPO_DRAWTIME);
1753  asp_local[1] = UI_view2d_grid_resolution_y__values(v2d);
1754  asp = asp_local;
1755  }
1756  }
1757 
1758  snap_increment_apply_ex(t, max_index, increment_dist, asp, r_val, r_val);
1759 }
1760 
1761 bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val)
1762 {
1763  if (!activeSnap(t)) {
1764  return false;
1765  }
1766 
1767  if (!(t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && !doForceIncrementSnap(t)) {
1768  return false;
1769  }
1770 
1771  if (t->spacetype != SPACE_VIEW3D && validSnap(t)) {
1772  /* Only do something if using absolute or incremental grid snapping
1773  * and there is no valid snap point. */
1774  return false;
1775  }
1776 
1777  if (use_local_space) {
1778  BLI_assert(t->idx_max == 2);
1779  mul_m3_v3(t->spacemtx_inv, r_val);
1780  }
1781 
1782  float increment_dist = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
1783  snap_increment_apply(t, t->idx_max, increment_dist, r_val);
1784 
1785  if (use_local_space) {
1786  mul_m3_v3(t->spacemtx, r_val);
1787  }
1788 
1789  return true;
1790 }
1791 
1792 bool transform_snap_increment(const TransInfo *t, float *r_val)
1793 {
1794  return transform_snap_increment_ex(t, false, r_val);
1795 }
1796 
1798 {
1799  if (activeSnap(t) && (!transformModeUseSnap(t) ||
1800  (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
1801  return (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
1802  }
1803 
1804  return 0.0f;
1805 }
1806 
1809 /* -------------------------------------------------------------------- */
1814  const float p1[3],
1815  const float p2[3])
1816 {
1817  return len_squared_v3v3(p1, p2);
1818 }
1819 
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:793
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:550
General operations, lookup, etc. for blender objects.
void BKE_object_eval_transform_all(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *object)
const struct BoundBox * BKE_object_boundbox_get(struct Object *ob)
Definition: object.cc:3684
bool BKE_object_is_in_editmode(const struct Object *ob)
bool BKE_scene_uses_blender_workbench(const struct Scene *scene)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define ATTR_FALLTHROUGH
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:239
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE int max_ii(int a, int b)
MINLINE float square_f(float a)
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
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:237
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 int BLI_rcti_size_x(const struct rcti *rct)
Definition: BLI_rect.h:186
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNPACK2(a)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define POINTER_FROM_UINT(i)
#define NODE_SELECT
#define NODE_ACTIVE
@ OB_SOLID
@ OB_RENDER
@ OB_MODE_PARTICLE_EDIT
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_ARMATURE
@ OB_MESH
@ OB_CURVES_LEGACY
eSnapTargetSelect
@ SCE_SNAP_TARGET_NOT_ACTIVE
@ SCE_SNAP_TARGET_NOT_NONEDITED
@ SCE_SNAP_TARGET_ONLY_SELECTABLE
@ SCE_SNAP_TARGET_ALL
@ SCE_SNAP_TARGET_NOT_SELECTED
@ SCE_SNAP_TARGET_NOT_EDITED
eSnapFlag
@ SCE_SNAP_PEEL_OBJECT
@ SCE_SNAP_TO_INCLUDE_EDITED
@ SCE_SNAP_NOT_TO_ACTIVE
@ SCE_SNAP
@ SCE_SNAP_TO_INCLUDE_NONEDITED
@ SCE_SNAP_PROJECT
@ SCE_SNAP_ROTATE
@ SCE_SNAP_ABS_GRID
@ SCE_SNAP_BACKFACE_CULLING
@ SCE_SNAP_TO_ONLY_SELECTABLE
eSnapSourceSelect
@ SCE_SNAP_SOURCE_MEDIAN
@ SCE_SNAP_SOURCE_CLOSEST
@ SCE_SNAP_SOURCE_ACTIVE
@ SCE_SNAP_SOURCE_CENTER
@ SCE_SNAP_TRANSFORM_MODE_SCALE
@ SCE_SNAP_TRANSFORM_MODE_ROTATE
@ SCE_SNAP_TRANSFORM_MODE_TRANSLATE
eSnapMode
@ SCE_SNAP_MODE_FACE_NEAREST
@ SCE_SNAP_MODE_VERTEX
@ SCE_SNAP_MODE_INCREMENT
@ SCE_SNAP_MODE_NODE_Y
@ SCE_SNAP_MODE_FACE_RAYCAST
@ SCE_SNAP_MODE_VOLUME
@ SCE_SNAP_MODE_GRID
@ SCE_SNAP_MODE_EDGE_PERPENDICULAR
@ SCE_SNAP_MODE_NONE
@ SCE_SNAP_MODE_GEOM
@ SCE_SNAP_MODE_NODE_X
@ SPACE_ACTION
@ SPACE_NODE
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SIPO_DRAWTIME
@ SI_MODE_UV
@ 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.cc:2177
NodeBorder
Definition: ED_node.h:29
@ NODE_LEFT
Definition: ED_node.h:32
@ NODE_RIGHT
Definition: ED_node.h:33
@ NODE_BOTTOM
Definition: ED_node.h:31
@ NODE_TOP
Definition: ED_node.h:30
@ TFM_RESIZE
Definition: ED_transform.h:32
@ TFM_EDGE_SLIDE
Definition: ED_transform.h:59
@ TFM_VERT_SLIDE
Definition: ED_transform.h:60
@ TFM_ROTATION
Definition: ED_transform.h:31
@ TFM_SEQ_SLIDE
Definition: ED_transform.h:61
@ TFM_TRANSLATION
Definition: ED_transform.h:30
eSnapMode ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, struct Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const eSnapMode snap_to, const struct SnapObjectParams *params, const float init_co[3], const float mval[2], const float prev_co[3], float *dist_px, float r_loc[3], float r_no[3])
bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx, struct Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const struct SnapObjectParams *params, const float mval[2], float ray_depth, bool sort, ListBase *r_hit_list)
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)
SnapObjectContext * ED_transform_snap_object_context_create(struct Scene *scene, int flag)
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
bool ED_uvedit_nearest_uv_multi(const struct View2D *v2d, const struct Scene *scene, struct Object **objects, uint objects_len, const int mval[2], const bool ignore_selected, 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:234
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:217
void ED_view3d_cursor_snap_draw_util(struct 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], eSnapMode snap_elem_type)
void immUniformColor4ubv(const unsigned char rgba[4])
void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b)
void immUnbindProgram(void)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat(void)
void imm_drawcircball(const float cent[3], float radius, const float tmat[4][4], uint pos)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
_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 y
_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 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
void GPU_matrix_pop_projection(void)
Definition: gpu_matrix.cc:140
void GPU_matrix_push_projection(void)
Definition: gpu_matrix.cc:133
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:201
@ GPU_SHADER_3D_UNIFORM_COLOR
Definition: GPU_shader.h:230
@ GPU_BLEND_NONE
Definition: GPU_state.h:60
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:62
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:39
@ GPU_DEPTH_LESS_EQUAL
Definition: GPU_state.h:86
@ GPU_DEPTH_NONE
Definition: GPU_state.h:83
void GPU_depth_test(eGPUDepthTest test)
Definition: gpu_state.cc:65
@ 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:25
@ TH_TRANSFORM
Definition: UI_resources.h:76
@ TH_VERTEX_SIZE
Definition: UI_resources.h:81
@ TH_SELECT
Definition: UI_resources.h:72
@ TH_SEQ_ACTIVE
Definition: UI_resources.h:198
@ TH_ACTIVE
Definition: UI_resources.h:73
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
Definition: resources.c:1323
float UI_GetThemeValuef(int colorid)
Definition: resources.c:1141
void UI_view2d_view_to_region_rcti(const struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL()
void UI_view2d_view_to_region_fl(const struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) 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.cc:450
float UI_view2d_grid_resolution_y__values(const struct View2D *v2d)
Definition: view2d_draw.cc:460
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
@ KM_SHIFT
Definition: WM_types.h:238
bool BM_elem_cb_check_hflag_disabled(BMElem *ele, void *user_data)
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
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
unsigned int U
Definition: btGjkEpa3.h:78
bool closest(btVector3 &v)
OperationNode * node
Scene scene
void * user_data
bNodeTree * ntree
uint pos
uint col
IconTextureDrawCall normal
IconTextureDrawCall border
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define fabsf(x)
Definition: metal/compat.h:219
T abs(const T &a)
return ret
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
Definition: rna_access.c:2879
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2153
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3402
short SEQ_tool_settings_snap_mode_get(Scene *scene)
Definition: sequencer.c:352
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)
#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t)
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
struct BMVert * v
Definition: bmesh_class.h:153
struct BMLoop * next
Definition: bmesh_class.h:233
struct Object * object
float vec[8][3]
void * first
Definition: DNA_listBase.h:31
float obmat[4][4]
float viewinv[4][4]
struct SnapObjectHitDepth * next
struct bNodeTree * edittree
short snap_face_nearest_steps
char snap_transform_mode_flag
float smtx[3][3]
float axismtx[3][3]
TransDataExtension * ext
struct Object * ob
View3DShading shading
struct Base * basact
ListBase nodes
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
uint8_t modifier
Definition: WM_types.h:693
short type
Definition: WM_types.h:678
struct PointerRNA * ptr
double PIL_check_seconds_timer(void)
Definition: time.c:64
conversion and adaptation of different datablocks to a common struct.
TransConvertTypeInfo TransConvertType_Cursor3D
TransConvertTypeInfo TransConvertType_Mesh
@ TD_SELECTED
@ TD_SKIP
void constraintTransLim(const TransInfo *t, TransData *td)
static void snap_increment_apply_ex(const TransInfo *UNUSED(t), const int max_index, const float increment_val, const float aspect[3], const float loc[3], float r_out[3])
bool transformModeUseSnap(const TransInfo *t)
bool usingSnappingNormal(const TransInfo *t)
static void TargetSnapCenter(TransInfo *t)
static eSnapTargetSelect snap_target_select_from_spacetype(TransInfo *t)
bool transform_snap_grid(TransInfo *t, float *val)
eSnapMode snapObjectsTransform(TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3])
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])
static void TargetSnapActive(TransInfo *t)
static void snap_calc_node_fn(TransInfo *t, float *vec)
void addSnapPoint(TransInfo *t)
bool validSnap(const TransInfo *t)
bool activeSnap_SnappingIndividual(const TransInfo *t)
bool transform_snap_increment(const TransInfo *t, float *r_val)
static void snap_calc_sequencer_fn(TransInfo *t, float *vec)
void freeSnapping(TransInfo *t)
static void snap_increment_apply(const TransInfo *t, const int max_index, const float increment_dist, float *r_val)
static eSnapMode snap_mode_from_spacetype(TransInfo *t)
eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
void applySnappingIndividual(TransInfo *t)
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 applySnappingAsGroup(TransInfo *t, float *vec)
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 bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select)
static void TargetSnapOffset(TransInfo *t, TransData *td)
static void applyFaceNearest(TransInfo *t, TransDataContainer *tc, TransData *td)
void getSnapPoint(const TransInfo *t, float vec[3])
bool activeSnap_SnappingAsGroup(const TransInfo *t)
static NodeBorder snapNodeBorder(eSnapMode snap_node_mode)
static void TargetSnapClosest(TransInfo *t)
static bool doForceIncrementSnap(const TransInfo *t)
eRedrawFlag updateSelectedSnapPoint(TransInfo *t)
float transform_snap_increment_get(const TransInfo *t)
bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val)
static bool snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *region, const int mval[2], eSnapTargetSelect snap_target_select, float r_loc[2], float *r_dist_px, char *r_node_border)
static bool snap_use_backface_culling(const TransInfo *t)
static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td)
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 snap_calc_uv_fn(TransInfo *t, float *vec)
static void initSnappingMode(TransInfo *t)
static eSnapFlag snap_flag_from_spacetype(TransInfo *t)
void resetSnapping(TransInfo *t)
bool activeSnap(const TransInfo *t)
static void snap_calc_view3d_fn(TransInfo *t, float *vec)
bool transform_snap_sequencer_calc(struct TransInfo *t)
void transform_snap_sequencer_data_free(struct TransSeqSnapData *data)
#define SNAP_MIN_DISTANCE
Definition: transform_snap.h:9
struct TransSeqSnapData * transform_snap_sequencer_data_alloc(const TransInfo *t)
@ EVT_TABKEY
@ MOUSEMOVE
void wmOrtho2_region_pixelspace(const ARegion *region)
Definition: wm_subwindow.c:103