Blender  V2.93
transform_mode_edge_slide.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 <stdlib.h>
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLI_math.h"
29 #include "BLI_string.h"
30 #include "BLI_utildefines_stack.h"
31 
32 #include "BKE_context.h"
33 #include "BKE_editmesh.h"
34 #include "BKE_editmesh_bvh.h"
35 #include "BKE_unit.h"
36 
37 #include "GPU_immediate.h"
38 #include "GPU_matrix.h"
39 #include "GPU_state.h"
40 
41 #include "ED_mesh.h"
42 #include "ED_screen.h"
43 
44 #include "WM_api.h"
45 #include "WM_types.h"
46 
47 #include "UI_interface.h"
48 #include "UI_resources.h"
49 
50 #include "BLT_translation.h"
51 
52 #include "transform.h"
53 #include "transform_constraints.h"
54 #include "transform_convert.h"
55 #include "transform_mode.h"
56 #include "transform_snap.h"
57 
58 /* -------------------------------------------------------------------- */
62 typedef struct TransDataEdgeSlideVert {
64  struct BMVert *v;
66  float v_co_orig[3];
67  /* end generic */
68 
69  float edge_len;
70 
71  struct BMVert *v_side[2];
72 
73  /* add origvert.co to get the original locations */
74  float dir_side[2][3];
75 
76  int loop_nr;
78 
79 typedef struct EdgeSlideData {
81  int totsv;
82 
83  int mval_start[2], mval_end[2];
85 
89 
90 typedef struct EdgeSlideParams {
91  float perc;
92 
93  bool use_even;
94  bool flipped;
96 
104 {
106  if (tc->custom.mode.data) {
107  return tc;
108  }
109  }
110  BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid");
111  return NULL;
112 }
113 
115 {
117  return tc->custom.mode.data;
118 }
119 
121 {
123 
124  setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
125 
126  /* setCustomPoints isn't normally changing as the mouse moves,
127  * in this case apply mouse input immediately so we don't refresh
128  * with the value from the previous points */
129  applyMouseInput(t, &t->mouse, t->mval, t->values);
130 }
131 
133 {
134  BMIter iter;
135  BMEdge *e_iter;
136 
137  BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
138  if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT) && e_iter != e) {
139  return e_iter;
140  }
141  }
142 
143  return NULL;
144 }
145 
146 /* Interpolates along a line made up of 2 segments (used for edge slide). */
148  float p[3], const float v1[3], const float v2[3], const float v3[3], float t)
149 {
150  float t_mid, t_delta;
151 
152  /* could be pre-calculated */
153  t_mid = line_point_factor_v3(v2, v1, v3);
154 
155  t_delta = t - t_mid;
156  if (t_delta < 0.0f) {
157  if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
158  copy_v3_v3(p, v2);
159  }
160  else {
161  interp_v3_v3v3(p, v1, v2, t / t_mid);
162  }
163  }
164  else {
165  t = t - t_mid;
166  t_mid = 1.0f - t_mid;
167 
168  if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
169  copy_v3_v3(p, v3);
170  }
171  else {
172  interp_v3_v3v3(p, v2, v3, t / t_mid);
173  }
174  }
175 }
176 
181 static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], float r_co[3])
182 {
183  /* skip adjacent edges */
184  BMLoop *l_first = l_tmp->next;
185  BMLoop *l_last = l_tmp->prev;
186  BMLoop *l_iter;
187  float dist = FLT_MAX;
188  bool found = false;
189 
190  l_iter = l_first;
191  do {
192  float tvec[3];
193  if (isect_line_plane_v3(tvec, l_iter->v->co, l_iter->next->v->co, l_tmp->v->co, plane_no)) {
194  const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co);
195  /* allow some overlap to avoid missing the intersection because of float precision */
196  if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) {
197  /* likelihood of multiple intersections per ngon is quite low,
198  * it would have to loop back on its self, but better support it
199  * so check for the closest opposite edge */
200  const float tdist = len_v3v3(l_tmp->v->co, tvec);
201  if (tdist < dist) {
202  copy_v3_v3(r_co, tvec);
203  dist = tdist;
204  found = true;
205  }
206  }
207  }
208  } while ((l_iter = l_iter->next) != l_last);
209 
210  return found;
211 }
212 
221  BMVert *v, BMLoop *l, BMEdge *e_prev, BMEdge *e_next, float r_slide_vec[3])
222 {
223  BMLoop *l_first;
224  float vec_accum[3] = {0.0f, 0.0f, 0.0f};
225  float vec_accum_len = 0.0f;
226  int i = 0;
227 
228  BLI_assert(BM_edge_share_vert(e_prev, e_next) == v);
230 
231  l_first = l;
232  do {
234 
235  if (l->e == e_next) {
236  if (i) {
237  normalize_v3_length(vec_accum, vec_accum_len / (float)i);
238  }
239  else {
240  /* When there is no edge to slide along,
241  * we must slide along the vector defined by the face we're attach to */
242  BMLoop *l_tmp = BM_face_vert_share_loop(l_first->f, v);
243 
244  BLI_assert(ELEM(l_tmp->e, e_prev, e_next) && ELEM(l_tmp->prev->e, e_prev, e_next));
245 
246  if (l_tmp->f->len == 4) {
247  /* we could use code below, but in this case
248  * sliding diagonally across the quad works well */
249  sub_v3_v3v3(vec_accum, l_tmp->next->next->v->co, v->co);
250  }
251  else {
252  float tdir[3];
253  BM_loop_calc_face_direction(l_tmp, tdir);
254  cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir);
255 #if 0
256  /* rough guess, we can do better! */
257  normalize_v3_length(vec_accum,
258  (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f);
259 #else
260  /* be clever, check the opposite ngon edge to slide into.
261  * this gives best results */
262  {
263  float tvec[3];
264  float dist;
265 
266  if (bm_loop_calc_opposite_co(l_tmp, tdir, tvec)) {
267  dist = len_v3v3(l_tmp->v->co, tvec);
268  }
269  else {
270  dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f;
271  }
272 
273  normalize_v3_length(vec_accum, dist);
274  }
275 #endif
276  }
277  }
278 
279  copy_v3_v3(r_slide_vec, vec_accum);
280  return l;
281  }
282 
283  /* accumulate the normalized edge vector,
284  * normalize so some edges don't skew the result */
285  float tvec[3];
286  sub_v3_v3v3(tvec, BM_edge_other_vert(l->e, v)->co, v->co);
287  vec_accum_len += normalize_v3(tvec);
288  add_v3_v3(vec_accum, tvec);
289  i += 1;
290 
291  if (BM_loop_other_edge_loop(l, v)->e == e_next) {
292  if (i) {
293  normalize_v3_length(vec_accum, vec_accum_len / (float)i);
294  }
295 
296  copy_v3_v3(r_slide_vec, vec_accum);
297  return BM_loop_other_edge_loop(l, v);
298  }
299 
300  } while ((l != l->radial_next) && ((l = l->radial_next) != l_first));
301 
302  if (i) {
303  normalize_v3_length(vec_accum, vec_accum_len / (float)i);
304  }
305 
306  copy_v3_v3(r_slide_vec, vec_accum);
307 
308  return NULL;
309 }
310 
315  TransDataContainer *tc,
316  EdgeSlideData *sld,
317  const int *sv_table,
318  const int loop_nr,
319  const float mval[2],
320  const bool use_occlude_geometry,
321  const bool use_calc_direction)
322 {
325  ARegion *region = t->region;
326  View3D *v3d = NULL;
327  RegionView3D *rv3d = NULL;
328  float projectMat[4][4];
329  BMBVHTree *bmbvh;
330 
331  /* only for use_calc_direction */
332  float(*loop_dir)[3] = NULL, *loop_maxdist = NULL;
333 
334  float mval_start[2], mval_end[2];
335  float mval_dir[3], dist_best_sq;
336 
337  if (t->spacetype == SPACE_VIEW3D) {
338  /* background mode support */
339  v3d = t->area ? t->area->spacedata.first : NULL;
340  rv3d = t->region ? t->region->regiondata : NULL;
341  }
342 
343  if (!rv3d) {
344  /* ok, let's try to survive this */
345  unit_m4(projectMat);
346  }
347  else {
348  ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
349  }
350 
351  if (use_occlude_geometry) {
353  }
354  else {
355  bmbvh = NULL;
356  }
357 
358  /* find mouse vectors, the global one, and one per loop in case we have
359  * multiple loops selected, in case they are oriented different */
360  zero_v3(mval_dir);
361  dist_best_sq = -1.0f;
362 
363  if (use_calc_direction) {
364  loop_dir = MEM_callocN(sizeof(float[3]) * loop_nr, "sv loop_dir");
365  loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
366  copy_vn_fl(loop_maxdist, loop_nr, -1.0f);
367  }
368 
369  sv = &sld->sv[0];
370  for (int i = 0; i < sld->totsv; i++, sv++) {
371  BMIter iter_other;
372  BMEdge *e;
373  BMVert *v = sv->v;
374 
375  UNUSED_VARS_NDEBUG(sv_table); /* silence warning */
376  BLI_assert(i == sv_table[BM_elem_index_get(v)]);
377 
378  /* search cross edges for visible edge to the mouse cursor,
379  * then use the shared vertex to calculate screen vector*/
380  BM_ITER_ELEM (e, &iter_other, v, BM_EDGES_OF_VERT) {
381  /* screen-space coords */
382  float sco_a[3], sco_b[3];
383  float dist_sq;
384  int l_nr;
385 
387  continue;
388  }
389 
390  /* This test is only relevant if object is not wire-drawn! See T32068. */
391  bool is_visible = !use_occlude_geometry ||
392  BMBVH_EdgeVisible(bmbvh, e, t->depsgraph, region, v3d, tc->obedit);
393 
394  if (!is_visible && !use_calc_direction) {
395  continue;
396  }
397 
398  if (sv->v_side[1]) {
399  ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, sco_b, projectMat);
400  }
401  else {
402  add_v3_v3v3(sco_b, v->co, sv->dir_side[1]);
403  ED_view3d_project_float_v3_m4(region, sco_b, sco_b, projectMat);
404  }
405 
406  if (sv->v_side[0]) {
407  ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, sco_a, projectMat);
408  }
409  else {
410  add_v3_v3v3(sco_a, v->co, sv->dir_side[0]);
411  ED_view3d_project_float_v3_m4(region, sco_a, sco_a, projectMat);
412  }
413 
414  /* global direction */
415  dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a);
416  if (is_visible) {
417  if ((dist_best_sq == -1.0f) ||
418  /* intentionally use 2d size on 3d vector */
419  (dist_sq < dist_best_sq && (len_squared_v2v2(sco_b, sco_a) > 0.1f))) {
420  dist_best_sq = dist_sq;
421  sub_v3_v3v3(mval_dir, sco_b, sco_a);
422  }
423  }
424 
425  if (use_calc_direction) {
426  /* per loop direction */
427  l_nr = sv->loop_nr;
428  if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) {
429  loop_maxdist[l_nr] = dist_sq;
430  sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
431  }
432  }
433  }
434  }
435 
436  if (use_calc_direction) {
437  int i;
438  sv = &sld->sv[0];
439  for (i = 0; i < sld->totsv; i++, sv++) {
440  /* switch a/b if loop direction is different from global direction */
441  int l_nr = sv->loop_nr;
442  if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
443  swap_v3_v3(sv->dir_side[0], sv->dir_side[1]);
444  SWAP(BMVert *, sv->v_side[0], sv->v_side[1]);
445  }
446  }
447 
448  MEM_freeN(loop_dir);
449  MEM_freeN(loop_maxdist);
450  }
451 
452  /* possible all of the edge loops are pointing directly at the view */
453  if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
454  mval_dir[0] = 0.0f;
455  mval_dir[1] = 100.0f;
456  }
457 
458  /* zero out start */
459  zero_v2(mval_start);
460 
461  /* dir holds a vector along edge loop */
462  copy_v2_v2(mval_end, mval_dir);
463  mul_v2_fl(mval_end, 0.5f);
464 
465  sld->mval_start[0] = t->mval[0] + mval_start[0];
466  sld->mval_start[1] = t->mval[1] + mval_start[1];
467 
468  sld->mval_end[0] = t->mval[0] + mval_end[0];
469  sld->mval_end[1] = t->mval[1] + mval_end[1];
470 
471  if (bmbvh) {
472  BKE_bmbvh_free(bmbvh);
473  }
474 }
475 
477  TransDataContainer *tc,
478  EdgeSlideData *sld,
479  const float mval[2])
480 {
481  TransDataEdgeSlideVert *sv = sld->sv;
482 
483  if (sld->totsv > 0) {
484  ARegion *region = t->region;
485  RegionView3D *rv3d = NULL;
486  float projectMat[4][4];
487 
488  int i = 0;
489 
490  float v_proj[2];
491  float dist_sq = 0;
492  float dist_min_sq = FLT_MAX;
493 
494  if (t->spacetype == SPACE_VIEW3D) {
495  /* background mode support */
496  rv3d = t->region ? t->region->regiondata : NULL;
497  }
498 
499  if (!rv3d) {
500  /* ok, let's try to survive this */
501  unit_m4(projectMat);
502  }
503  else {
504  ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
505  }
506 
507  for (i = 0; i < sld->totsv; i++, sv++) {
508  /* Set length */
509  sv->edge_len = len_v3v3(sv->dir_side[0], sv->dir_side[1]);
510 
511  ED_view3d_project_float_v2_m4(region, sv->v->co, v_proj, projectMat);
512  dist_sq = len_squared_v2v2(mval, v_proj);
513  if (dist_sq < dist_min_sq) {
514  dist_min_sq = dist_sq;
515  sld->curr_sv_index = i;
516  }
517  }
518  }
519  else {
520  sld->curr_sv_index = 0;
521  }
522 }
523 
525 {
527  BMesh *bm = em->bm;
528  BMIter iter;
529  BMEdge *e;
530  BMVert *v;
531  TransDataEdgeSlideVert *sv_array;
532  int sv_tot;
533  int *sv_table; /* BMVert -> sv_array index */
534  EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
535  const float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
536  int numsel, i, loop_nr;
537  bool use_occlude_geometry = false;
538  View3D *v3d = NULL;
539  RegionView3D *rv3d = NULL;
540 
541  sld->curr_sv_index = 0;
542 
543  /*ensure valid selection*/
544  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
546  BMIter iter2;
547  numsel = 0;
548  BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
550  /* BMESH_TODO: this is probably very evil,
551  * set v->e to a selected edge*/
552  v->e = e;
553 
554  numsel++;
555  }
556  }
557 
558  if (numsel == 0 || numsel > 2) {
559  /* Invalid edge selection. */
560  MEM_freeN(sld);
561  return NULL;
562  }
563  }
564  }
565 
566  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
568  /* note, any edge with loops can work, but we won't get predictable results, so bail out */
570  /* can edges with at least once face user */
571  MEM_freeN(sld);
572  return NULL;
573  }
574  }
575  }
576 
577  sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
578 
579 #define INDEX_UNSET -1
580 #define INDEX_INVALID -2
581 
582  {
583  int j = 0;
584  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
587  sv_table[i] = INDEX_UNSET;
588  j += 1;
589  }
590  else {
592  sv_table[i] = INDEX_INVALID;
593  }
594  BM_elem_index_set(v, i); /* set_inline */
595  }
597 
598  if (!j) {
599  MEM_freeN(sld);
600  MEM_freeN(sv_table);
601  return NULL;
602  }
603  sv_tot = j;
604  }
605 
606  sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array");
607  loop_nr = 0;
608 
609  STACK_DECLARE(sv_array);
610  STACK_INIT(sv_array, sv_tot);
611 
612  while (1) {
613  float vec_a[3], vec_b[3];
614  BMLoop *l_a, *l_b;
615  BMLoop *l_a_prev, *l_b_prev;
616  BMVert *v_first;
617  /* If this succeeds call get_next_loop()
618  * which calculates the direction to slide based on clever checks.
619  *
620  * otherwise we simply use 'e_dir' as an edge-rail.
621  * (which is better when the attached edge is a boundary, see: T40422)
622  */
623 #define EDGESLIDE_VERT_IS_INNER(v, e_dir) \
624  ((BM_edge_is_boundary(e_dir) == false) && (BM_vert_edge_count_nonwire(v) == 2))
625 
626  v = NULL;
627  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
629  break;
630  }
631  }
632 
633  if (!v) {
634  break;
635  }
636 
637  if (!v->e) {
638  continue;
639  }
640 
641  v_first = v;
642 
643  /*walk along the edge loop*/
644  e = v->e;
645 
646  /*first, rewind*/
647  do {
648  e = get_other_edge(v, e);
649  if (!e) {
650  e = v->e;
651  break;
652  }
653 
655  break;
656  }
657 
658  v = BM_edge_other_vert(e, v);
659  } while (e != v_first->e);
660 
662 
663  l_a = e->l;
664  l_b = e->l->radial_next;
665 
666  /* regarding e_next, use get_next_loop()'s improved interpolation where possible */
667  {
668  BMEdge *e_next = get_other_edge(v, e);
669  if (e_next) {
670  get_next_loop(v, l_a, e, e_next, vec_a);
671  }
672  else {
673  BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
674  if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
675  get_next_loop(v, l_a, e, l_tmp->e, vec_a);
676  }
677  else {
678  sub_v3_v3v3(vec_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
679  }
680  }
681  }
682 
683  /* !BM_edge_is_boundary(e); */
684  if (l_b != l_a) {
685  BMEdge *e_next = get_other_edge(v, e);
686  if (e_next) {
687  get_next_loop(v, l_b, e, e_next, vec_b);
688  }
689  else {
690  BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
691  if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
692  get_next_loop(v, l_b, e, l_tmp->e, vec_b);
693  }
694  else {
695  sub_v3_v3v3(vec_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
696  }
697  }
698  }
699  else {
700  l_b = NULL;
701  }
702 
703  l_a_prev = NULL;
704  l_b_prev = NULL;
705 
706 #define SV_FROM_VERT(v) \
707  ((sv_table[BM_elem_index_get(v)] == INDEX_UNSET) ? \
708  ((void)(sv_table[BM_elem_index_get(v)] = STACK_SIZE(sv_array)), \
709  STACK_PUSH_RET_PTR(sv_array)) : \
710  (&sv_array[sv_table[BM_elem_index_get(v)]]))
711 
712  /*iterate over the loop*/
713  v_first = v;
714  do {
715  bool l_a_ok_prev;
716  bool l_b_ok_prev;
718  BMVert *v_prev;
719  BMEdge *e_prev;
720 
721  /* XXX, 'sv' will initialize multiple times, this is suspicious. see T34024. */
722  BLI_assert(v != NULL);
724  sv = SV_FROM_VERT(v);
725  sv->v = v;
726  copy_v3_v3(sv->v_co_orig, v->co);
727  sv->loop_nr = loop_nr;
728 
729  if (l_a || l_a_prev) {
730  BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v);
731  sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
732  copy_v3_v3(sv->dir_side[0], vec_a);
733  }
734 
735  if (l_b || l_b_prev) {
736  BMLoop *l_tmp = BM_loop_other_edge_loop(l_b ? l_b : l_b_prev, v);
737  sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
738  copy_v3_v3(sv->dir_side[1], vec_b);
739  }
740 
741  v_prev = v;
742  v = BM_edge_other_vert(e, v);
743 
744  e_prev = e;
745  e = get_other_edge(v, e);
746 
747  if (!e) {
748  BLI_assert(v != NULL);
749 
751  sv = SV_FROM_VERT(v);
752 
753  sv->v = v;
754  copy_v3_v3(sv->v_co_orig, v->co);
755  sv->loop_nr = loop_nr;
756 
757  if (l_a) {
758  BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
759  sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
760  if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
761  get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_side[0]);
762  }
763  else {
764  sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
765  }
766  }
767 
768  if (l_b) {
769  BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
770  sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
771  if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
772  get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_side[1]);
773  }
774  else {
775  sub_v3_v3v3(sv->dir_side[1], sv->v_side[1]->co, v->co);
776  }
777  }
778 
781 
782  break;
783  }
784  l_a_ok_prev = (l_a != NULL);
785  l_b_ok_prev = (l_b != NULL);
786 
787  l_a_prev = l_a;
788  l_b_prev = l_b;
789 
790  if (l_a) {
791  l_a = get_next_loop(v, l_a, e_prev, e, vec_a);
792  }
793  else {
794  zero_v3(vec_a);
795  }
796 
797  if (l_b) {
798  l_b = get_next_loop(v, l_b, e_prev, e, vec_b);
799  }
800  else {
801  zero_v3(vec_b);
802  }
803 
804  if (l_a && l_b) {
805  /* pass */
806  }
807  else {
808  if (l_a || l_b) {
809  /* find the opposite loop if it was missing previously */
810  if (l_a == NULL && l_b && (l_b->radial_next != l_b)) {
811  l_a = l_b->radial_next;
812  }
813  else if (l_b == NULL && l_a && (l_a->radial_next != l_a)) {
814  l_b = l_a->radial_next;
815  }
816  }
817  else if (e->l != NULL) {
818  /* if there are non-contiguous faces, we can still recover
819  * the loops of the new edges faces */
820 
821  /* note!, the behavior in this case means edges may move in opposite directions,
822  * this could be made to work more usefully. */
823 
824  if (l_a_ok_prev) {
825  l_a = e->l;
826  l_b = (l_a->radial_next != l_a) ? l_a->radial_next : NULL;
827  }
828  else if (l_b_ok_prev) {
829  l_b = e->l;
830  l_a = (l_b->radial_next != l_b) ? l_b->radial_next : NULL;
831  }
832  }
833 
834  if (!l_a_ok_prev && l_a) {
835  get_next_loop(v, l_a, e, e_prev, vec_a);
836  }
837  if (!l_b_ok_prev && l_b) {
838  get_next_loop(v, l_b, e, e_prev, vec_b);
839  }
840  }
841 
844  } while ((e != v_first->e) && (l_a || l_b));
845 
846 #undef SV_FROM_VERT
847 #undef INDEX_UNSET
848 #undef INDEX_INVALID
849 
850  loop_nr++;
851 
852 #undef EDGESLIDE_VERT_IS_INNER
853  }
854 
855  /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
856 
857  BLI_assert(STACK_SIZE(sv_array) == (uint)sv_tot);
858 
859  sld->sv = sv_array;
860  sld->totsv = sv_tot;
861 
862  /* use for visibility checks */
863  if (t->spacetype == SPACE_VIEW3D) {
864  v3d = t->area ? t->area->spacedata.first : NULL;
865  rv3d = t->region ? t->region->regiondata : NULL;
866  use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
867  !XRAY_ENABLED(v3d));
868  }
869 
870  calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
871 
872  if (rv3d) {
873  calcEdgeSlide_even(t, tc, sld, mval);
874  }
875 
876  MEM_freeN(sv_table);
877 
878  return sld;
879 }
880 
886 {
888  BMesh *bm = em->bm;
889  BMIter iter;
890  BMEdge *e;
891  TransDataEdgeSlideVert *sv_array;
892  int sv_tot;
893  int *sv_table; /* BMVert -> sv_array index */
894  EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
895  const float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
896  int loop_nr;
897  bool use_occlude_geometry = false;
898  View3D *v3d = NULL;
899  RegionView3D *rv3d = NULL;
900 
901  if (t->spacetype == SPACE_VIEW3D) {
902  /* background mode support */
903  v3d = t->area ? t->area->spacedata.first : NULL;
904  rv3d = t->region ? t->region->regiondata : NULL;
905  }
906 
907  sld->curr_sv_index = 0;
908  /* ensure valid selection */
909  {
910  int i = 0, j = 0;
911  BMVert *v;
912 
913  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
915  float len_sq_max = -1.0f;
916  BMIter iter2;
917  BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
919  float len_sq = BM_edge_calc_length_squared(e);
920  if (len_sq > len_sq_max) {
921  len_sq_max = len_sq;
922  v->e = e;
923  }
924  }
925  }
926 
927  if (len_sq_max != -1.0f) {
928  j++;
929  }
930  }
931  BM_elem_index_set(v, i); /* set_inline */
932  }
934 
935  if (!j) {
936  MEM_freeN(sld);
937  return NULL;
938  }
939 
940  sv_tot = j;
941  }
942 
943  BLI_assert(sv_tot != 0);
944  /* over alloc */
945  sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * bm->totvertsel, "sv_array");
946 
947  /* Same loop for all loops, weak but we don't connect loops in this case. */
948  loop_nr = 1;
949 
950  sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
951 
952  {
953  int i = 0, j = 0;
954  BMVert *v;
955 
956  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
957  sv_table[i] = -1;
958  if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) {
959  if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) {
961  sv = &sv_array[j];
962  sv->v = v;
963  copy_v3_v3(sv->v_co_orig, v->co);
964  sv->v_side[0] = BM_edge_other_vert(v->e, v);
965  sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
966  sv->loop_nr = 0;
967  sv_table[i] = j;
968  j += 1;
969  }
970  }
971  }
972  }
973 
974  /* check for wire vertices,
975  * interpolate the directions of wire verts between non-wire verts */
976  if (sv_tot != bm->totvert) {
977  const int sv_tot_nowire = sv_tot;
978  TransDataEdgeSlideVert *sv_iter = sv_array;
979 
980  for (int i = 0; i < sv_tot_nowire; i++, sv_iter++) {
981  BMIter eiter;
982  BM_ITER_ELEM (e, &eiter, sv_iter->v, BM_EDGES_OF_VERT) {
983  /* walk over wire */
984  TransDataEdgeSlideVert *sv_end = NULL;
985  BMEdge *e_step = e;
986  BMVert *v = sv_iter->v;
987  int j;
988 
989  j = sv_tot;
990 
991  while (1) {
992  BMVert *v_other = BM_edge_other_vert(e_step, v);
993  int endpoint = ((sv_table[BM_elem_index_get(v_other)] != -1) +
994  (BM_vert_is_edge_pair(v_other) == false));
995 
996  if ((BM_elem_flag_test(e_step, BM_ELEM_SELECT) &&
997  BM_elem_flag_test(v_other, BM_ELEM_SELECT)) &&
998  (endpoint == 0)) {
999  /* scan down the list */
1001  BLI_assert(sv_table[BM_elem_index_get(v_other)] == -1);
1002  sv_table[BM_elem_index_get(v_other)] = j;
1003  sv = &sv_array[j];
1004  sv->v = v_other;
1005  copy_v3_v3(sv->v_co_orig, v_other->co);
1006  copy_v3_v3(sv->dir_side[0], sv_iter->dir_side[0]);
1007  j++;
1008 
1009  /* advance! */
1010  v = v_other;
1011  e_step = BM_DISK_EDGE_NEXT(e_step, v_other);
1012  }
1013  else {
1014  if ((endpoint == 2) && (sv_tot != j)) {
1015  BLI_assert(BM_elem_index_get(v_other) != -1);
1016  sv_end = &sv_array[sv_table[BM_elem_index_get(v_other)]];
1017  }
1018  break;
1019  }
1020  }
1021 
1022  if (sv_end) {
1023  int sv_tot_prev = sv_tot;
1024  const float *co_src = sv_iter->v->co;
1025  const float *co_dst = sv_end->v->co;
1026  const float *dir_src = sv_iter->dir_side[0];
1027  const float *dir_dst = sv_end->dir_side[0];
1028  sv_tot = j;
1029 
1030  while (j-- != sv_tot_prev) {
1031  float factor;
1032  factor = line_point_factor_v3(sv_array[j].v->co, co_src, co_dst);
1033  interp_v3_v3v3(sv_array[j].dir_side[0], dir_src, dir_dst, factor);
1034  }
1035  }
1036  }
1037  }
1038  }
1039 
1040  /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
1041 
1042  sld->sv = sv_array;
1043  sld->totsv = sv_tot;
1044 
1045  /* use for visibility checks */
1046  if (t->spacetype == SPACE_VIEW3D) {
1047  v3d = t->area ? t->area->spacedata.first : NULL;
1048  rv3d = t->region ? t->region->regiondata : NULL;
1049  use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
1050  !XRAY_ENABLED(v3d));
1051  }
1052 
1053  calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
1054 
1055  if (rv3d) {
1056  calcEdgeSlide_even(t, tc, sld, mval);
1057  }
1058 
1059  MEM_freeN(sv_table);
1060 
1061  return sld;
1062 }
1063 
1066  TransCustomData *custom_data)
1067 {
1068  EdgeSlideData *sld = custom_data->data;
1069 
1070  if (sld == NULL) {
1071  return;
1072  }
1073 
1074  MEM_freeN(sld->sv);
1075  MEM_freeN(sld);
1076 
1077  custom_data->data = NULL;
1078 }
1079 
1080 static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
1081 {
1082  if (t->mode == TFM_EDGE_SLIDE) {
1083  EdgeSlideParams *slp = t->custom.mode.data;
1084 
1085  if (slp) {
1086  switch (event->type) {
1087  case EVT_EKEY:
1088  if (event->val == KM_PRESS) {
1089  slp->use_even = !slp->use_even;
1091  return TREDRAW_HARD;
1092  }
1093  break;
1094  case EVT_FKEY:
1095  if (event->val == KM_PRESS) {
1096  slp->flipped = !slp->flipped;
1098  return TREDRAW_HARD;
1099  }
1100  break;
1101  case EVT_CKEY:
1102  /* use like a modifier key */
1103  if (event->val == KM_PRESS) {
1104  t->flag ^= T_ALT_TRANSFORM;
1106  return TREDRAW_HARD;
1107  }
1108  break;
1109  case EVT_MODAL_MAP:
1110 #if 0
1111  switch (event->val) {
1113  sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
1114  return TREDRAW_HARD;
1116  sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
1117  return TREDRAW_HARD;
1118  }
1119 #endif
1120  break;
1121  case MOUSEMOVE:
1123  break;
1124  default:
1125  break;
1126  }
1127  }
1128  }
1129  return TREDRAW_NOTHING;
1130 }
1131 
1133 {
1134  if (t->mode != TFM_EDGE_SLIDE) {
1135  return;
1136  }
1137 
1139  if (sld == NULL) {
1140  return;
1141  }
1142 
1143  const EdgeSlideParams *slp = t->custom.mode.data;
1144  const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
1145 
1146  const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
1147 
1149 
1151 
1152  GPU_matrix_push();
1154 
1156 
1158 
1159  if (slp->use_even == true) {
1160  /* Even mode */
1161  float co_a[3], co_b[3], co_mark[3];
1162  TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
1163  const float fac = (slp->perc + 1.0f) / 2.0f;
1164  const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
1165  const float guide_size = ctrl_size - 0.5f;
1166  const int alpha_shade = -30;
1167 
1168  add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]);
1169  add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]);
1170 
1171  GPU_line_width(line_size);
1174  if (curr_sv->v_side[0]) {
1175  immVertex3fv(pos, curr_sv->v_side[0]->co);
1176  immVertex3fv(pos, curr_sv->v_co_orig);
1177  }
1178  if (curr_sv->v_side[1]) {
1179  immVertex3fv(pos, curr_sv->v_side[1]->co);
1180  immVertex3fv(pos, curr_sv->v_co_orig);
1181  }
1182  immEnd();
1183 
1184  {
1185  float *co_test = NULL;
1186  if (slp->flipped) {
1187  if (curr_sv->v_side[1]) {
1188  co_test = curr_sv->v_side[1]->co;
1189  }
1190  }
1191  else {
1192  if (curr_sv->v_side[0]) {
1193  co_test = curr_sv->v_side[0]->co;
1194  }
1195  }
1196 
1197  if (co_test != NULL) {
1198  immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
1199  GPU_point_size(ctrl_size);
1201  immVertex3fv(pos, co_test);
1202  immEnd();
1203  }
1204  }
1205 
1206  immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
1207  GPU_point_size(guide_size);
1209  interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
1210  immVertex3fv(pos, co_mark);
1211  immEnd();
1212  }
1213  else if (is_clamp == false) {
1214  const int side_index = sld->curr_side_unclamp;
1216  int i;
1217  const int alpha_shade = -160;
1218 
1219  GPU_line_width(line_size);
1221  immBegin(GPU_PRIM_LINES, sld->totsv * 2);
1222 
1223  /* TODO(campbell): Loop over all verts */
1224  sv = sld->sv;
1225  for (i = 0; i < sld->totsv; i++, sv++) {
1226  float a[3], b[3];
1227 
1228  if (!is_zero_v3(sv->dir_side[side_index])) {
1229  copy_v3_v3(a, sv->dir_side[side_index]);
1230  }
1231  else {
1232  copy_v3_v3(a, sv->dir_side[!side_index]);
1233  }
1234 
1235  mul_v3_fl(a, 100.0f);
1236  negate_v3_v3(b, a);
1237  add_v3_v3(a, sv->v_co_orig);
1238  add_v3_v3(b, sv->v_co_orig);
1239 
1240  immVertex3fv(pos, a);
1241  immVertex3fv(pos, b);
1242  }
1243  immEnd();
1244  }
1245  else {
1246  /* Common case. */
1247  TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
1248  const int alpha_shade = -160;
1249 
1250  float co_dir[3];
1251  add_v3_v3v3(co_dir, curr_sv->v_co_orig, curr_sv->dir_side[sld->curr_side_unclamp]);
1252 
1253  GPU_line_width(line_size);
1256  immVertex3fv(pos, curr_sv->v_co_orig);
1257  immVertex3fv(pos, co_dir);
1258  immEnd();
1259  }
1260 
1261  immUnbindProgram();
1262 
1263  GPU_matrix_pop();
1264 
1266 
1268 }
1269 
1270 static void edge_slide_snap_apply(TransInfo *t, float *value)
1271 {
1273  EdgeSlideParams *slp = t->custom.mode.data;
1274  EdgeSlideData *sld_active = tc->custom.mode.data;
1275  TransDataEdgeSlideVert *sv = &sld_active->sv[sld_active->curr_sv_index];
1276  float snap_point[3], co_orig[3], co_dest[2][3], dvec[3];
1277 
1278  copy_v3_v3(co_orig, sv->v_co_orig);
1279  add_v3_v3v3(co_dest[0], co_orig, sv->dir_side[0]);
1280  add_v3_v3v3(co_dest[1], co_orig, sv->dir_side[1]);
1281  if (tc->use_local_mat) {
1282  mul_m4_v3(tc->mat, co_orig);
1283  mul_m4_v3(tc->mat, co_dest[0]);
1284  mul_m4_v3(tc->mat, co_dest[1]);
1285  }
1286 
1287  getSnapPoint(t, dvec);
1288  sub_v3_v3(dvec, t->tsnap.snapTarget);
1289  add_v3_v3v3(snap_point, co_orig, dvec);
1290 
1291  float perc = *value;
1292  int side_index;
1293  float t_mid;
1294  if (slp->use_even == false) {
1295  const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
1296  if (is_clamp) {
1297  side_index = perc < 0.0f;
1298  }
1299  else {
1300  side_index = sld_active->curr_side_unclamp;
1301  }
1302  }
1303  else {
1304  /* Could be pre-calculated. */
1305  t_mid = line_point_factor_v3((float[3]){0.0f, 0.0f, 0.0f}, sv->dir_side[0], sv->dir_side[1]);
1306 
1307  float t_snap = line_point_factor_v3(snap_point, co_dest[0], co_dest[1]);
1308  side_index = t_snap >= t_mid;
1309  }
1310 
1311  if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) {
1312  float co_dir[3];
1313  sub_v3_v3v3(co_dir, co_dest[side_index], co_orig);
1314  normalize_v3(co_dir);
1315  if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) {
1317  }
1318  else {
1320  }
1321  add_v3_v3v3(snap_point, co_orig, dvec);
1322  }
1323 
1324  perc = line_point_factor_v3(snap_point, co_orig, co_dest[side_index]);
1325  if (slp->use_even == false) {
1326  if (side_index) {
1327  perc *= -1;
1328  }
1329  }
1330  else {
1331  if (!side_index) {
1332  perc = (1.0f - perc) * t_mid;
1333  }
1334  else {
1335  perc = perc * (1.0f - t_mid) + t_mid;
1336  }
1337 
1338  if (slp->flipped) {
1339  perc = 1.0f - perc;
1340  }
1341 
1342  perc = (2 * perc) - 1.0f;
1343 
1344  if (!slp->flipped) {
1345  perc *= -1;
1346  }
1347  }
1348 
1349  *value = perc;
1350 }
1351 
1352 static void doEdgeSlide(TransInfo *t, float perc)
1353 {
1354  EdgeSlideParams *slp = t->custom.mode.data;
1355  EdgeSlideData *sld_active = edgeSlideFirstGet(t);
1356 
1357  slp->perc = perc;
1358 
1359  if (slp->use_even == false) {
1360  const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
1361  if (is_clamp) {
1362  const int side_index = (perc < 0.0f);
1363  const float perc_final = fabsf(perc);
1365  EdgeSlideData *sld = tc->custom.mode.data;
1366 
1367  if (sld == NULL) {
1368  continue;
1369  }
1370 
1371  TransDataEdgeSlideVert *sv = sld->sv;
1372  for (int i = 0; i < sld->totsv; i++, sv++) {
1373  madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
1374  }
1375  sld->curr_side_unclamp = side_index;
1376  }
1377  }
1378  else {
1379  const float perc_init = fabsf(perc) *
1380  ((sld_active->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
1381  const int side_index = sld_active->curr_side_unclamp;
1383  EdgeSlideData *sld = tc->custom.mode.data;
1384 
1385  if (sld == NULL) {
1386  continue;
1387  }
1388 
1389  TransDataEdgeSlideVert *sv = sld->sv;
1390  for (int i = 0; i < sld->totsv; i++, sv++) {
1391  float dir_flip[3];
1392  float perc_final = perc_init;
1393  if (!is_zero_v3(sv->dir_side[side_index])) {
1394  copy_v3_v3(dir_flip, sv->dir_side[side_index]);
1395  }
1396  else {
1397  copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
1398  perc_final *= -1;
1399  }
1400  madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
1401  }
1402  }
1403  }
1404  }
1405  else {
1416  TransDataEdgeSlideVert *curr_sv = &sld_active->sv[sld_active->curr_sv_index];
1417  const float curr_length_perc = curr_sv->edge_len *
1418  (((slp->flipped ? perc : -perc) + 1.0f) / 2.0f);
1419 
1420  float co_a[3];
1421  float co_b[3];
1422 
1424  EdgeSlideData *sld = tc->custom.mode.data;
1425 
1426  if (sld == NULL) {
1427  continue;
1428  }
1429 
1430  TransDataEdgeSlideVert *sv = sld->sv;
1431  for (int i = 0; i < sld->totsv; i++, sv++) {
1432  if (sv->edge_len > FLT_EPSILON) {
1433  const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
1434 
1435  add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
1436  add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
1437 
1438  if (slp->flipped) {
1439  interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
1440  }
1441  else {
1442  interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac);
1443  }
1444  }
1445  }
1446  }
1447  }
1448 }
1449 
1450 static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
1451 {
1452  char str[UI_MAX_DRAW_STR];
1453  size_t ofs = 0;
1454  float final;
1455  EdgeSlideParams *slp = t->custom.mode.data;
1456  bool flipped = slp->flipped;
1457  bool use_even = slp->use_even;
1458  const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
1459  const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
1460 
1461  final = t->values[0];
1462 
1463  applySnapping(t, &final);
1464  if (!validSnap(t)) {
1465  transform_snap_increment(t, &final);
1466  }
1467 
1468  /* only do this so out of range values are not displayed */
1469  if (is_constrained) {
1470  CLAMP(final, -1.0f, 1.0f);
1471  }
1472 
1473  applyNumInput(&t->num, &final);
1474 
1475  t->values_final[0] = final;
1476 
1477  /* header string */
1478  ofs += BLI_strncpy_rlen(str + ofs, TIP_("Edge Slide: "), sizeof(str) - ofs);
1479  if (hasNumInput(&t->num)) {
1480  char c[NUM_STR_REP_LEN];
1481  outputNumInput(&(t->num), c, &t->scene->unit);
1482  ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
1483  }
1484  else {
1485  ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
1486  }
1487  ofs += BLI_snprintf(
1488  str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even));
1489  if (use_even) {
1490  ofs += BLI_snprintf(
1491  str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped));
1492  }
1493  ofs += BLI_snprintf(
1494  str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
1495  /* done with header string */
1496 
1497  /* do stuff here */
1498  doEdgeSlide(t, final);
1499 
1500  recalcData(t);
1501 
1502  ED_area_status_text(t->area, str);
1503 }
1504 
1506  TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
1507 {
1508  EdgeSlideData *sld;
1509  bool ok = false;
1510 
1511  t->mode = TFM_EDGE_SLIDE;
1512  t->transform = applyEdgeSlide;
1513  t->handleEvent = handleEventEdgeSlide;
1514  t->tsnap.applySnap = edge_slide_snap_apply;
1515  t->tsnap.distance = transform_snap_distance_len_squared_fn;
1516 
1517  {
1518  EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
1519  slp->use_even = use_even;
1520  slp->flipped = flipped;
1521  /* happens to be best for single-sided */
1522  if (use_double_side == false) {
1523  slp->flipped = !flipped;
1524  }
1525  slp->perc = 0.0f;
1526 
1527  if (!use_clamp) {
1528  t->flag |= T_ALT_TRANSFORM;
1529  }
1530 
1531  t->custom.mode.data = slp;
1532  t->custom.mode.use_free = true;
1533  }
1534 
1536  sld = use_double_side ? createEdgeSlideVerts_double_side(t, tc) :
1538  if (sld) {
1539  tc->custom.mode.data = sld;
1540  tc->custom.mode.free_cb = freeEdgeSlideVerts;
1541  ok = true;
1542  }
1543  }
1544 
1545  if (!ok) {
1546  t->state = TRANS_CANCEL;
1547  return;
1548  }
1549 
1550  /* set custom point first if you want value to be initialized by init */
1553 
1554  t->idx_max = 0;
1555  t->num.idx_max = 0;
1556  t->snap[0] = 0.1f;
1557  t->snap[1] = t->snap[0] * 0.1f;
1558 
1559  copy_v3_fl(t->num.val_inc, t->snap[0]);
1560  t->num.unit_sys = t->scene->unit.system;
1561  t->num.unit_type[0] = B_UNIT_NONE;
1562 
1563  t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
1564 }
1565 
1567 {
1568  initEdgeSlide_ex(t, true, false, false, true);
1569 }
typedef float(TangentPoint)[2]
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
@ BMBVH_RESPECT_HIDDEN
void BKE_bmbvh_free(BMBVHTree *tree)
Definition: editmesh_bvh.c:186
BMBVHTree * BKE_bmbvh_new_from_editmesh(struct BMEditMesh *em, int flag, const float(*cos_cage)[3], const bool cos_cage_free)
Definition: editmesh_bvh.c:47
@ B_UNIT_NONE
Definition: BKE_unit.h:78
#define BLI_assert(a)
Definition: BLI_assert.h:58
MINLINE float min_ff(float a, float b)
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
Definition: math_geom.c:3449
bool isect_line_plane_v3(float r_isect_co[3], const float l1[3], const float l2[3], const float plane_co[3], const float plane_no[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_geom.c:2191
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:338
void unit_m4(float m[4][4])
Definition: rct.c:1140
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void copy_vn_fl(float *array_tar, const int size, const float val)
Definition: math_vector.c:1410
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
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 void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
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 void negate_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v2(float r[2])
MINLINE void swap_v3_v3(float a[3], float b[3])
MINLINE float normalize_v3_length(float r[3], const float unit_scale)
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:187
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
#define STACK_DECLARE(stack)
#define STACK_INIT(stack, tot)
#define STACK_SIZE(stack)
#define TIP_(msgid)
@ OB_WIRE
#define SCE_SNAP_MODE_FACE
#define SCE_SNAP_MODE_EDGE
@ SPACE_VIEW3D
bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e, struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, struct Object *obedit)
void outputNumInput(NumInput *n, char *str, struct UnitSettings *unit_settings)
Definition: numinput.c:102
#define NUM_STR_REP_LEN
Definition: ED_numinput.h:27
bool applyNumInput(NumInput *n, float *vec)
Definition: numinput.c:207
bool hasNumInput(const NumInput *n)
Definition: numinput.c:185
void ED_area_status_text(ScrArea *area, const char *str)
Definition: area.c:815
@ TFM_EDGE_SLIDE
Definition: ED_transform.h:74
#define XRAY_ENABLED(v3d)
Definition: ED_view3d.h:710
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float r_pmat[4][4])
void ED_view3d_project_float_v3_m4(const struct ARegion *region, const float co[3], float r_co[3], float mat[4][4])
void ED_view3d_project_float_v2_m4(const struct ARegion *region, const float co[3], float r_co[2], float mat[4][4])
void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
void immUnbindProgram(void)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immBeginAtMost(GPUPrimType, uint max_vertex_len)
GPUVertFormat * immVertexFormat(void)
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immEnd(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 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
_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 v1
void GPU_matrix_pop(void)
Definition: gpu_matrix.cc:142
#define GPU_matrix_mul(x)
Definition: GPU_matrix.h:223
void GPU_matrix_push(void)
Definition: gpu_matrix.cc:135
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:36
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:35
@ 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
void GPU_line_width(float width)
Definition: gpu_state.cc:173
void GPU_point_size(float size)
Definition: gpu_state.cc:179
@ 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.
Group RGB to Bright Vector Camera CLAMP
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:90
@ TH_FACEDOT_SIZE
Definition: UI_resources.h:112
@ TH_EDGE_SELECT
Definition: UI_resources.h:101
@ TH_OUTLINE_WIDTH
Definition: UI_resources.h:98
@ TH_SELECT
Definition: UI_resources.h:88
float UI_GetThemeValuef(int colorid)
Definition: resources.c:1164
#define KM_PRESS
Definition: WM_types.h:242
#define BM_DISK_EDGE_NEXT(e, v)
Definition: bmesh_class.h:556
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:125
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
float BM_edge_calc_length_squared(const BMEdge *e)
Definition: bmesh_query.c:721
BMVert * BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
Definition: bmesh_query.c:1366
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
BM_loop_calc_face_direction.
Definition: bmesh_query.c:1657
float BM_edge_calc_length(const BMEdge *e)
Definition: bmesh_query.c:713
bool BM_vert_is_edge_pair(const BMVert *v)
Definition: bmesh_query.c:771
BMLoop * BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
Definition: bmesh_query.c:69
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
Definition: bmesh_query.c:1403
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define str(s)
uint pos
#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
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
struct BMesh * bm
Definition: BKE_editmesh.h:52
int len
Definition: bmesh_class.h:279
float no[3]
Definition: bmesh_class.h:280
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
int totvert
Definition: bmesh_class.h:297
char elem_index_dirty
Definition: bmesh_class.h:305
int totvertsel
Definition: bmesh_class.h:298
TransDataEdgeSlideVert * sv
TransCustomData mode
Definition: transform.h:426
TransCustomDataContainer custom
Definition: transform.h:501
struct Object * obedit
Definition: transform.h:461
float mat[4][4]
Definition: transform.h:463
short val
Definition: WM_types.h:579
short type
Definition: WM_types.h:577
@ INPUT_CUSTOM_RATIO_FLIP
Definition: transform.h:740
void recalcData(TransInfo *t)
#define TRANS_DATA_CONTAINER_FIRST_OK(t)
Definition: transform.h:808
eRedrawFlag
Definition: transform.h:197
@ TREDRAW_NOTHING
Definition: transform.h:198
@ TREDRAW_HARD
Definition: transform.h:199
void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3])
void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2])
@ T_ALT_TRANSFORM
Definition: transform.h:140
@ T_NO_PROJECT
Definition: transform.h:135
@ T_NO_CONSTRAINT
Definition: transform.h:106
@ TRANS_CANCEL
Definition: transform.h:193
@ TFM_MODAL_EDGESLIDE_UP
Definition: transform.h:278
@ TFM_MODAL_EDGESLIDE_DOWN
Definition: transform.h:279
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition: transform.h:813
void transform_constraint_snap_axis_to_face(const TransInfo *t, const float axis[3], float r_out[3])
void transform_constraint_snap_axis_to_edge(const TransInfo *t, const float axis[3], float r_out[3])
conversion and adaptation of different datablocks to a common struct.
transform modes used by different operators.
static BMEdge * get_other_edge(BMVert *v, BMEdge *e)
struct TransDataEdgeSlideVert TransDataEdgeSlideVert
#define EDGESLIDE_VERT_IS_INNER(v, e_dir)
#define INDEX_INVALID
static void edge_slide_snap_apply(TransInfo *t, float *value)
static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], float r_co[3])
static EdgeSlideData * createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *tc)
static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], float t)
static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
static void calcEdgeSlide_mval_range(TransInfo *t, TransDataContainer *tc, EdgeSlideData *sld, const int *sv_table, const int loop_nr, const float mval[2], const bool use_occlude_geometry, const bool use_calc_direction)
static void calcEdgeSlideCustomPoints(struct TransInfo *t)
static EdgeSlideData * edgeSlideFirstGet(TransInfo *t)
#define INDEX_UNSET
static void calcEdgeSlide_even(TransInfo *t, TransDataContainer *tc, EdgeSlideData *sld, const float mval[2])
void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
struct EdgeSlideParams EdgeSlideParams
static TransDataContainer * edge_slide_container_first_ok(TransInfo *t)
static void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransDataContainer *UNUSED(tc), TransCustomData *custom_data)
static EdgeSlideData * createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *tc)
static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
void drawEdgeSlide(TransInfo *t)
#define SV_FROM_VERT(v)
static BMLoop * get_next_loop(BMVert *v, BMLoop *l, BMEdge *e_prev, BMEdge *e_next, float r_slide_vec[3])
static void doEdgeSlide(TransInfo *t, float perc)
void initEdgeSlide(TransInfo *t)
struct EdgeSlideData EdgeSlideData
void applySnapping(TransInfo *t, float *vec)
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])
bool validSnap(const TransInfo *t)
void getSnapPoint(const TransInfo *t, float vec[3])
@ EVT_EKEY
@ EVT_MODAL_MAP
@ EVT_FKEY
@ EVT_CKEY
@ MOUSEMOVE
const char * WM_bool_as_string(bool test)
Definition: wm_keymap.c:2003