Blender  V2.93
uvedit_rip.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 
21 #include <math.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "MEM_guardedalloc.h"
26 
27 #include "BLI_ghash.h"
28 #include "BLI_linklist_stack.h"
29 #include "BLI_math.h"
30 #include "BLI_math_vector.h"
31 #include "BLI_utildefines.h"
32 
33 #include "DNA_image_types.h"
34 #include "DNA_mesh_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_space_types.h"
40 
41 #include "BKE_context.h"
42 #include "BKE_customdata.h"
43 #include "BKE_editmesh.h"
44 #include "BKE_layer.h"
45 #include "BKE_report.h"
46 
47 #include "DEG_depsgraph.h"
48 
49 #include "ED_screen.h"
50 #include "ED_transform.h"
51 #include "ED_uvedit.h"
52 
53 #include "RNA_access.h"
54 #include "RNA_define.h"
55 
56 #include "WM_api.h"
57 #include "WM_types.h"
58 
59 #include "UI_view2d.h"
60 
61 #include "uvedit_intern.h"
62 
63 /* -------------------------------------------------------------------- */
68 typedef struct ULData {
91  uint side : 1;
99 
101 BLI_STATIC_ASSERT(sizeof(ULData) <= sizeof(int), "");
102 
104 {
105  return (ULData *)&l->head.index;
106 }
107 
110 /* -------------------------------------------------------------------- */
115  const int cd_loop_uv_offset)
116 {
117  BMLoop *l_other = NULL;
118  BMLoop *l_iter = l_src->radial_next;
119  if (l_iter != l_src) {
120  do {
121  if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG) && UL(l_iter)->is_select_edge &&
122  BM_loop_uv_share_edge_check(l_src, l_iter, cd_loop_uv_offset)) {
123  /* Check UV's are contiguous. */
124  if (l_other == NULL) {
125  l_other = l_iter;
126  }
127  else {
128  /* Only use when there is a single alternative. */
129  l_other = NULL;
130  break;
131  }
132  }
133  } while ((l_iter = l_iter->radial_next) != l_src);
134  }
135  return l_other;
136 }
137 
139  BMVert *v_src,
140  const int cd_loop_uv_offset)
141 {
142  BLI_assert(BM_vert_in_edge(l_src->e, v_src));
143  BMLoop *l_other = NULL;
144  BMLoop *l_iter = l_src->radial_next;
145  if (l_iter != l_src) {
146  do {
147  if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG) &&
148  BM_loop_uv_share_edge_check(l_src, l_iter, cd_loop_uv_offset)) {
149  /* Check UV's are contiguous. */
150  if (l_other == NULL) {
151  l_other = l_iter;
152  }
153  else {
154  /* Only use when there is a single alternative. */
155  l_other = NULL;
156  break;
157  }
158  }
159  } while ((l_iter = l_iter->radial_next) != l_src);
160  }
161  if (l_other != NULL) {
162  if (l_other->v == v_src) {
163  /* do nothing. */
164  }
165  else if (l_other->next->v == v_src) {
166  l_other = l_other->next;
167  }
168  else if (l_other->prev->v == v_src) {
169  l_other = l_other->prev;
170  }
171  else {
173  }
174  }
175  return l_other;
176 }
177 
181 static BMLoop *bm_vert_step_fan_loop_uv(BMLoop *l, BMEdge **e_step, const int cd_loop_uv_offset)
182 {
183  BMEdge *e_prev = *e_step;
184  BMLoop *l_next;
185  if (l->e == e_prev) {
186  l_next = l->prev;
187  }
188  else if (l->prev->e == e_prev) {
189  l_next = l;
190  }
191  else {
193  return NULL;
194  }
195 
196  *e_step = l_next->e;
197 
198  return bm_loop_find_other_fan_loop_with_visible_face(l_next, l->v, cd_loop_uv_offset);
199 }
200 
201 static void bm_loop_uv_select_single_vert_validate(BMLoop *l_init, const int cd_loop_uv_offset)
202 {
203  const MLoopUV *luv_init = BM_ELEM_CD_GET_VOID_P(l_init, cd_loop_uv_offset);
204  BMIter liter;
205  BMLoop *l;
206  bool is_single_vert = true;
207  BM_ITER_ELEM (l, &liter, l_init->v, BM_LOOPS_OF_VERT) {
208  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
209  if (equals_v2v2(luv_init->uv, luv->uv)) {
210  if (UL(l->prev)->is_select_edge || UL(l)->is_select_edge) {
211  is_single_vert = false;
212  break;
213  }
214  }
215  }
216  if (is_single_vert == false) {
217  BM_ITER_ELEM (l, &liter, l_init->v, BM_LOOPS_OF_VERT) {
218  if (UL(l)->is_select_vert_single) {
219  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
220  if (equals_v2v2(luv_init->uv, luv->uv)) {
221  UL(l)->is_select_vert_single = false;
222  }
223  }
224  }
225  }
226 }
227 
235  const float dir[2],
236  const float aspect_y,
237  const int cd_loop_uv_offset,
238  float *r_corner_angle,
239  float *r_edge_angle,
240  int *r_edge_index)
241 {
242  /* Calculate 3 directions, return the shortest angle. */
243  float dir_test[3][2];
244  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
245  const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
246  const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
247 
248  sub_v2_v2v2(dir_test[0], luv->uv, luv_prev->uv);
249  sub_v2_v2v2(dir_test[2], luv->uv, luv_next->uv);
250  dir_test[0][1] /= aspect_y;
251  dir_test[2][1] /= aspect_y;
252 
253  normalize_v2(dir_test[0]);
254  normalize_v2(dir_test[2]);
255 
256  /* Calculate the orthogonal line (same as negating one, then adding). */
257  sub_v2_v2v2(dir_test[1], dir_test[0], dir_test[2]);
258  normalize_v2(dir_test[1]);
259 
260  /* Rotate 90 degrees. */
261  SWAP(float, dir_test[1][0], dir_test[1][1]);
262  dir_test[1][1] *= -1.0f;
263 
264  if (BM_face_uv_calc_cross(l->f, cd_loop_uv_offset) > 0.0f) {
265  negate_v2(dir_test[1]);
266  }
267 
268  const float angles[3] = {
269  angle_v2v2(dir, dir_test[0]),
270  angle_v2v2(dir, dir_test[1]),
271  angle_v2v2(dir, dir_test[2]),
272  };
273 
274  /* Set the corner values. */
275  *r_corner_angle = angles[1];
276 
277  /* Set the edge values. */
278  if (angles[0] < angles[2]) {
279  *r_edge_angle = angles[0];
280  *r_edge_index = -1;
281  }
282  else {
283  *r_edge_angle = angles[2];
284  *r_edge_index = 1;
285  }
286 }
287 
290 /* -------------------------------------------------------------------- */
294 typedef struct UVRipSingle {
298 
314  const float co[2],
315  const float aspect_y,
316  const int cd_loop_uv_offset)
317 {
318  UVRipSingle *rip = MEM_callocN(sizeof(*rip), __func__);
319  const float *co_center =
320  (((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_init_orig, cd_loop_uv_offset))->uv);
321  rip->loops = BLI_gset_ptr_new(__func__);
322 
323  /* Track the closest loop, start walking from this so in the event we have multiple
324  * disconnected fans, we can rip away loops connected to this one. */
325  BMLoop *l_init = NULL;
326  BMLoop *l_init_edge = NULL;
327  float corner_angle_best = FLT_MAX;
328  float edge_angle_best = FLT_MAX;
329  int edge_index_best = 0; /* -1 or +1 (never center). */
330 
331  /* Calculate the direction from the cursor with aspect correction. */
332  float dir_co[2];
333  sub_v2_v2v2(dir_co, co_center, co);
334  dir_co[1] /= aspect_y;
335  if (UNLIKELY(normalize_v2(dir_co) == 0.0)) {
336  dir_co[1] = 1.0f;
337  }
338 
339  int uv_fan_count_all = 0;
340  {
341  BMIter liter;
342  BMLoop *l;
343  BM_ITER_ELEM (l, &liter, l_init_orig->v, BM_LOOPS_OF_VERT) {
344  if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
345  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
346  if (equals_v2v2(co_center, luv->uv)) {
347  uv_fan_count_all += 1;
348  /* Clear at the same time. */
349  UL(l)->is_select_vert_single = true;
350  UL(l)->side = 0;
351  BLI_gset_add(rip->loops, l);
352 
353  /* Update `l_init_close` */
354  float corner_angle_test;
355  float edge_angle_test;
356  int edge_index_test;
358  dir_co,
359  aspect_y,
360  cd_loop_uv_offset,
361  &corner_angle_test,
362  &edge_angle_test,
363  &edge_index_test);
364  if ((corner_angle_best == FLT_MAX) || (corner_angle_test < corner_angle_best)) {
365  corner_angle_best = corner_angle_test;
366  l_init = l;
367  }
368 
369  /* Trick so we don't consider concave corners further away than they should be. */
370  edge_angle_test = min_ff(corner_angle_test, edge_angle_test);
371 
372  if ((edge_angle_best == FLT_MAX) || (edge_angle_test < edge_angle_best)) {
373  edge_angle_best = edge_angle_test;
374  edge_index_best = edge_index_test;
375  l_init_edge = l;
376  }
377  }
378  }
379  }
380  }
381 
382  /* Walk around the `l_init` in both directions of the UV fan. */
383  int uv_fan_count_contiguous = 1;
384  UL(l_init)->side = 1;
385  for (int i = 0; i < 2; i += 1) {
386  BMEdge *e_prev = i ? l_init->e : l_init->prev->e;
387  BMLoop *l_iter = l_init;
388  while (((l_iter = bm_vert_step_fan_loop_uv(l_iter, &e_prev, cd_loop_uv_offset)) != l_init) &&
389  (l_iter != NULL) && (UL(l_iter)->side == 0)) {
390  uv_fan_count_contiguous += 1;
391  /* Keep. */
392  UL(l_iter)->side = 1;
393  }
394  /* May be useful to know if the fan is closed, currently it's not needed. */
395 #if 0
396  if (l_iter == l_init) {
397  is_closed = true;
398  }
399 #endif
400  }
401 
402  if (uv_fan_count_contiguous != uv_fan_count_all) {
403  /* Simply rip off the current fan, all tagging is done. */
404  }
405  else {
406  GSetIterator gs_iter;
407  GSET_ITER (gs_iter, rip->loops) {
408  BMLoop *l = BLI_gsetIterator_getKey(&gs_iter);
409  UL(l)->side = 0;
410  }
411 
412  if (uv_fan_count_contiguous <= 2) {
413  /* Simple case, rip away the closest loop. */
414  UL(l_init)->side = 1;
415  }
416  else {
417  /* Rip away from the closest edge. */
418  BMLoop *l_radial_init = (edge_index_best == -1) ? l_init_edge->prev : l_init_edge;
419  BMLoop *l_radial_iter = l_radial_init;
420  do {
421  if (BM_loop_uv_share_edge_check(l_radial_init, l_radial_iter, cd_loop_uv_offset)) {
422  BMLoop *l = (l_radial_iter->v == l_init->v) ? l_radial_iter : l_radial_iter->next;
423  BLI_assert(l->v == l_init->v);
424  /* Keep. */
425  UL(l)->side = 1;
426  }
427  } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_init);
428  }
429  }
430 
431  return rip;
432 }
433 
435 {
436  BLI_gset_free(rip->loops, NULL);
437  MEM_freeN(rip);
438 }
439 
442 /* -------------------------------------------------------------------- */
446 typedef struct UVRipPairs {
450 
451 static void uv_rip_pairs_add(UVRipPairs *rip, BMLoop *l)
452 {
453  ULData *ul = UL(l);
455  BLI_assert(ul->in_rip_pairs == false);
456  ul->in_rip_pairs = true;
457  BLI_gset_add(rip->loops, l);
458 }
459 
461 {
462  ULData *ul = UL(l);
464  BLI_assert(ul->in_rip_pairs == true);
465  ul->in_rip_pairs = false;
466  BLI_gset_remove(rip->loops, l, NULL);
467 }
468 
473 static float uv_rip_pairs_calc_uv_angle(BMLoop *l_init,
474  uint side,
475  const float aspect_y,
476  const int cd_loop_uv_offset)
477 {
478  BMIter liter;
479  const MLoopUV *luv_init = BM_ELEM_CD_GET_VOID_P(l_init, cd_loop_uv_offset);
480  float angle_of_side = 0.0f;
481  BMLoop *l;
482  BM_ITER_ELEM (l, &liter, l_init->v, BM_LOOPS_OF_VERT) {
483  if (UL(l)->in_rip_pairs) {
484  if (UL(l)->side == side) {
485  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
486  if (equals_v2v2(luv_init->uv, luv->uv)) {
487  const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
488  const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
489  float dir_prev[2], dir_next[2];
490  sub_v2_v2v2(dir_prev, luv_prev->uv, luv->uv);
491  sub_v2_v2v2(dir_next, luv_next->uv, luv->uv);
492  dir_prev[1] /= aspect_y;
493  dir_next[1] /= aspect_y;
494  const float luv_angle = angle_v2v2(dir_prev, dir_next);
495  if (LIKELY(isfinite(luv_angle))) {
496  angle_of_side += luv_angle;
497  }
498  }
499  }
500  }
501  }
502  return angle_of_side;
503 }
504 
505 static int uv_rip_pairs_loop_count_on_side(BMLoop *l_init, uint side, const int cd_loop_uv_offset)
506 {
507  const MLoopUV *luv_init = BM_ELEM_CD_GET_VOID_P(l_init, cd_loop_uv_offset);
508  int count = 0;
509  BMIter liter;
510  BMLoop *l;
511  BM_ITER_ELEM (l, &liter, l_init->v, BM_LOOPS_OF_VERT) {
512  if (UL(l)->in_rip_pairs) {
513  if (UL(l)->side == side) {
514  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
515  if (equals_v2v2(luv_init->uv, luv->uv)) {
516  count += 1;
517  }
518  }
519  }
520  }
521  return count;
522 }
523 
525  BMLoop *l_target,
526  const float aspect_y,
527  const int cd_loop_uv_offset)
528 {
529  const int side_a = UL(l_switch)->side;
530  const int side_b = UL(l_target)->side;
531 
532  BLI_assert(UL(l_switch)->side != UL(l_target)->side);
533 
534  /* First, check if this is a simple grid topology,
535  * in that case always choose the adjacent edge. */
536  const int count_a = uv_rip_pairs_loop_count_on_side(l_switch, side_a, cd_loop_uv_offset);
537  const int count_b = uv_rip_pairs_loop_count_on_side(l_target, side_b, cd_loop_uv_offset);
538  if (count_a + count_b == 4) {
539  return count_a > count_b;
540  }
541 
542  const float angle_a_before = uv_rip_pairs_calc_uv_angle(
543  l_switch, side_a, aspect_y, cd_loop_uv_offset);
544  const float angle_b_before = uv_rip_pairs_calc_uv_angle(
545  l_target, side_b, aspect_y, cd_loop_uv_offset);
546 
547  UL(l_switch)->side = side_b;
548 
549  const float angle_a_after = uv_rip_pairs_calc_uv_angle(
550  l_switch, side_a, aspect_y, cd_loop_uv_offset);
551  const float angle_b_after = uv_rip_pairs_calc_uv_angle(
552  l_target, side_b, aspect_y, cd_loop_uv_offset);
553 
554  UL(l_switch)->side = side_a;
555 
556  return fabsf(angle_a_before - angle_b_before) > fabsf(angle_a_after - angle_b_after);
557 }
558 
568  const float aspect_y,
569  const int cd_loop_uv_offset)
570 {
571  UVRipPairs *rip = MEM_callocN(sizeof(*rip), __func__);
572  rip->loops = BLI_gset_ptr_new(__func__);
573 
574  /* We can rely on this stack being small, as we're walking down two sides of an edge loop,
575  * so the stack wont be much larger than the total number of fans at any one vertex. */
576  BLI_SMALLSTACK_DECLARE(stack, BMLoop *);
577 
578  /* Needed for cases when we walk onto loops which already have a side assigned,
579  * in this case we need to pick a better side (see #uv_rip_pairs_loop_change_sides_test)
580  * and put the loop back in the stack,
581  * which is needed in the case adjacent loops should also switch sides. */
582 #define UV_SET_SIDE_AND_REMOVE_FROM_RAIL(loop, side_value) \
583  { \
584  BLI_assert(UL(loop)->side_was_swapped == false); \
585  BLI_assert(UL(loop)->side != side_value); \
586  if (!UL(loop)->in_stack) { \
587  BLI_SMALLSTACK_PUSH(stack, loop); \
588  UL(loop)->in_stack = true; \
589  } \
590  if (UL(loop)->in_rip_pairs) { \
591  uv_rip_pairs_remove(rip, loop); \
592  } \
593  UL(loop)->side = side_value; \
594  UL(loop)->side_was_swapped = true; \
595  }
596 
597  /* Initialize the stack. */
598  BLI_SMALLSTACK_PUSH(stack, l_init);
599  UL(l_init)->in_stack = true;
600 
601  BMLoop *l_step;
602  while ((l_step = BLI_SMALLSTACK_POP(stack))) {
603  int side = UL(l_step)->side;
604  UL(l_step)->in_stack = false;
605 
606  /* Note that we could add all loops into the rip-pairs when adding into the stack,
607  * however this complicates removal, so add into the rip-pairs when popping from the stack. */
608  uv_rip_pairs_add(rip, l_step);
609 
610  /* Add to the other side if it exists. */
611  if (UL(l_step)->is_select_edge) {
613  cd_loop_uv_offset);
614  if (l_other != NULL) {
615  if (!UL(l_other)->in_rip_pairs && !UL(l_other)->in_stack) {
616  BLI_SMALLSTACK_PUSH(stack, l_other);
617  UL(l_other)->in_stack = true;
618  UL(l_other)->side = !side;
619  }
620  else {
621  if (UL(l_other)->side == side) {
622  if (UL(l_other)->side_was_swapped == false) {
623  UV_SET_SIDE_AND_REMOVE_FROM_RAIL(l_other, !side);
624  }
625  }
626  }
627  }
628 
629  /* Add the next loop along the edge on the same side. */
630  l_other = l_step->next;
631  if (!UL(l_other)->in_rip_pairs && !UL(l_other)->in_stack) {
632  BLI_SMALLSTACK_PUSH(stack, l_other);
633  UL(l_other)->in_stack = true;
634  UL(l_other)->side = side;
635  }
636  else {
637  if (UL(l_other)->side != side) {
638  if ((UL(l_other)->side_was_swapped == false) &&
639  uv_rip_pairs_loop_change_sides_test(l_other, l_step, aspect_y, cd_loop_uv_offset)) {
640  UV_SET_SIDE_AND_REMOVE_FROM_RAIL(l_other, side);
641  }
642  }
643  }
644  }
645 
646  /* Walk over the fan of loops, starting from `l_step` in both directions. */
647  for (int i = 0; i < 2; i++) {
648  BMLoop *l_radial_first = i ? l_step : l_step->prev;
649  if (l_radial_first != l_radial_first->radial_next) {
650  BMEdge *e_radial = l_radial_first->e;
651  BMLoop *l_radial_iter = l_radial_first->radial_next;
652  do {
653  /* Not a boundary and visible. */
654  if (!UL(l_radial_iter)->is_select_edge &&
655  BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
656  BMLoop *l_other = (l_radial_iter->v == l_step->v) ? l_radial_iter :
657  l_radial_iter->next;
658  BLI_assert(l_other->v == l_step->v);
659  if (BM_edge_uv_share_vert_check(e_radial, l_other, l_step, cd_loop_uv_offset)) {
660  if (!UL(l_other)->in_rip_pairs && !UL(l_other)->in_stack) {
661  BLI_SMALLSTACK_PUSH(stack, l_other);
662  UL(l_other)->in_stack = true;
663  UL(l_other)->side = side;
664  }
665  else {
666  if (UL(l_other)->side != side) {
667  if ((UL(l_other)->side_was_swapped == false) &&
669  l_other, l_step, aspect_y, cd_loop_uv_offset)) {
670  UV_SET_SIDE_AND_REMOVE_FROM_RAIL(l_other, side);
671  }
672  }
673  }
674  }
675  }
676  } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
677  }
678  }
679  }
680 
681 #undef UV_SET_SIDE_AND_REMOVE_FROM_RAIL
682 
683  return rip;
684 }
685 
686 static void uv_rip_pairs_free(UVRipPairs *rip)
687 {
688  BLI_gset_free(rip->loops, NULL);
689  MEM_freeN(rip);
690 }
691 
696  const int cd_loop_uv_offset,
697  float r_center[2],
698  float r_dir_side[2][2])
699 {
700  zero_v2(r_center);
701  int center_total = 0;
702  int side_total[2] = {0, 0};
703 
704  for (int i = 0; i < 2; i++) {
705  zero_v2(r_dir_side[i]);
706  }
707  GSetIterator gs_iter;
708  GSET_ITER (gs_iter, rip->loops) {
709  BMLoop *l = BLI_gsetIterator_getKey(&gs_iter);
710  int side = UL(l)->side;
711  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
712  add_v2_v2(r_center, luv->uv);
713 
714  float dir[2];
715  if (!UL(l)->is_select_edge) {
716  const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
717  sub_v2_v2v2(dir, luv_next->uv, luv->uv);
718  add_v2_v2(r_dir_side[side], dir);
719  }
720  if (!UL(l->prev)->is_select_edge) {
721  const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
722  sub_v2_v2v2(dir, luv_prev->uv, luv->uv);
723  add_v2_v2(r_dir_side[side], dir);
724  }
725  side_total[side] += 1;
726  }
727  center_total += BLI_gset_len(rip->loops);
728 
729  for (int i = 0; i < 2; i++) {
730  normalize_v2(r_dir_side[i]);
731  }
732  mul_v2_fl(r_center, 1.0f / center_total);
733 
734  /* If only a single side is selected, don't handle this rip-pairs. */
735  return side_total[0] && side_total[1];
736 }
737 
740 /* -------------------------------------------------------------------- */
747 static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const float aspect_y)
748 {
749  Mesh *me = (Mesh *)obedit->data;
750  BMEditMesh *em = me->edit_mesh;
751  BMesh *bm = em->bm;
752  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
753 
754  BMFace *efa;
755  BMIter iter, liter;
756  BMLoop *l;
757 
758  const ULData ul_clear = {0};
759 
760  bool changed = false;
761 
762  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
764  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
765  ULData *ul = UL(l);
766  *ul = ul_clear;
767  }
768  }
770 
771  bool is_select_all_any = false;
772  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
773  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
774  bool is_all = true;
775  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
776  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
777  if (luv->flag & MLOOPUV_VERTSEL) {
778  const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
779  const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
780  if (luv_next->flag & MLOOPUV_VERTSEL) {
781  UL(l)->is_select_edge = true;
782  }
783  else {
784  if ((luv_prev->flag & MLOOPUV_VERTSEL) == 0) {
785  /* #bm_loop_uv_select_single_vert_validate validates below. */
786  UL(l)->is_select_vert_single = true;
787  }
788  }
789  }
790  else {
791  is_all = false;
792  }
793  }
794  if (is_all) {
795  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
796  UL(l)->is_select_all = true;
797  }
798  is_select_all_any = true;
799  }
800  }
801  }
802 
803  /* Remove #ULData.is_select_vert_single when connected to selected edges. */
804  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
805  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
806  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
807  if (UL(l)->is_select_vert_single) {
808  bm_loop_uv_select_single_vert_validate(l, cd_loop_uv_offset);
809  }
810  }
811  }
812  }
813 
814  /* Special case: if we have selected faces, isolated them.
815  * This isn't a rip, however it's useful for users as a quick way
816  * to detach the selection.
817  *
818  * We could also extract an edge loop from the boundary
819  * however in practice it's not that useful, see T78751. */
820  if (is_select_all_any) {
821  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
822  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
823  if (!UL(l)->is_select_all) {
824  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
825  if (luv->flag & MLOOPUV_VERTSEL) {
826  luv->flag &= ~MLOOPUV_VERTSEL;
827  changed = true;
828  }
829  }
830  }
831  }
832  return changed;
833  }
834 
835  /* Extract loop pairs or single loops. */
836  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
837  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
838  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
839  if (UL(l)->is_select_edge) {
840  if (!UL(l)->in_rip_pairs) {
841  UVRipPairs *rip = uv_rip_pairs_from_loop(l, aspect_y, cd_loop_uv_offset);
842  float center[2];
843  float dir_cursor[2];
844  float dir_side[2][2];
845  int side_from_cursor = -1;
846  if (uv_rip_pairs_calc_center_and_direction(rip, cd_loop_uv_offset, center, dir_side)) {
847  for (int i = 0; i < 2; i++) {
848  sub_v2_v2v2(dir_cursor, center, co);
849  normalize_v2(dir_cursor);
850  }
851  side_from_cursor = (dot_v2v2(dir_side[0], dir_cursor) -
852  dot_v2v2(dir_side[1], dir_cursor)) < 0.0f;
853  }
854  GSetIterator gs_iter;
855  GSET_ITER (gs_iter, rip->loops) {
856  BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter);
857  ULData *ul = UL(l_iter);
858  if (ul->side == side_from_cursor) {
859  uvedit_uv_select_disable(scene, em, l_iter, cd_loop_uv_offset);
860  changed = true;
861  }
862  /* Ensure we don't operate on these again. */
863  *ul = ul_clear;
864  }
865  uv_rip_pairs_free(rip);
866  }
867  }
868  else if (UL(l)->is_select_vert_single) {
869  UVRipSingle *rip = uv_rip_single_from_loop(l, co, aspect_y, cd_loop_uv_offset);
870  /* We only ever use one side. */
871  const int side_from_cursor = 0;
872  GSetIterator gs_iter;
873  GSET_ITER (gs_iter, rip->loops) {
874  BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter);
875  ULData *ul = UL(l_iter);
876  if (ul->side == side_from_cursor) {
877  uvedit_uv_select_disable(scene, em, l_iter, cd_loop_uv_offset);
878  changed = true;
879  }
880  /* Ensure we don't operate on these again. */
881  *ul = ul_clear;
882  }
883  uv_rip_single_free(rip);
884  }
885  }
886  }
887  }
888  return changed;
889 }
890 
893 /* -------------------------------------------------------------------- */
897 static int uv_rip_exec(bContext *C, wmOperator *op)
898 {
901  ViewLayer *view_layer = CTX_data_view_layer(C);
902 
903  bool changed_multi = false;
904 
905  float co[2];
906  RNA_float_get_array(op->ptr, "location", co);
907 
908  float aspx, aspy;
909  {
910  /* Note that we only want to run this on the */
911  Object *obedit = CTX_data_edit_object(C);
912  ED_uvedit_get_aspect(obedit, &aspx, &aspy);
913  }
914  const float aspect_y = aspx / aspy;
915 
916  uint objects_len = 0;
918  view_layer, ((View3D *)NULL), &objects_len);
919 
920  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
921  Object *obedit = objects[ob_index];
922 
923  if (uv_rip_object(scene, obedit, co, aspect_y)) {
924  changed_multi = true;
925  uvedit_live_unwrap_update(sima, scene, obedit);
926  DEG_id_tag_update(obedit->data, 0);
928  }
929  }
930  MEM_freeN(objects);
931 
932  if (!changed_multi) {
933  BKE_report(op->reports, RPT_ERROR, "Rip failed");
934  return OPERATOR_CANCELLED;
935  }
936  return OPERATOR_FINISHED;
937 }
938 
939 static int uv_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
940 {
941  ARegion *region = CTX_wm_region(C);
942  float co[2];
943 
944  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
945  RNA_float_set_array(op->ptr, "location", co);
946 
947  return uv_rip_exec(C, op);
948 }
949 
951 {
952  /* identifiers */
953  ot->name = "UV Rip";
954  ot->description = "Rip selected vertices or a selected region";
955  ot->idname = "UV_OT_rip";
957 
958  /* api callbacks */
959  ot->exec = uv_rip_exec;
962 
963  /* translation data */
965 
966  /* properties */
968  ot->srna,
969  "location",
970  2,
971  NULL,
972  -FLT_MAX,
973  FLT_MAX,
974  "Location",
975  "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
976  -100.0f,
977  100.0f);
978 }
979 
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:800
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const struct CustomData *data, int type)
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:434
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_assert_unreachable()
Definition: BLI_assert.h:96
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
struct GSet GSet
Definition: BLI_ghash.h:189
unsigned int BLI_gset_len(GSet *gs) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1138
GSet * BLI_gset_ptr_new(const char *info)
#define GSET_ITER(gs_iter_, gset_)
Definition: BLI_ghash.h:268
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1216
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition: BLI_ghash.h:255
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:1160
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1211
MINLINE float min_ff(float a, float b)
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:483
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void negate_v2(float r[2])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float r[2])
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define UNLIKELY(x)
#define LIKELY(x)
void DEG_id_tag_update(struct ID *id, int flag)
@ CD_MLOOPUV
@ MLOOPUV_VERTSEL
Object is a sort of wrapper for general info.
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
bool ED_operator_uvedit(struct bContext *C)
Definition: screen_ops.c:511
void Transform_Properties(struct wmOperatorType *ot, int flags)
#define P_MIRROR_DUMMY
Definition: ED_transform.h:123
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy)
void uvedit_uv_select_disable(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, const int cd_loop_uv_offset)
bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa)
NSNotificationCenter * center
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
@ BM_LOOP
Definition: bmesh_class.h:385
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset)
Scene scene
int count
#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
bool isfinite(uchar)
Definition: image.cpp:44
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:6390
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3851
int index
Definition: bmesh_class.h:73
BMHeader head
Definition: bmesh_class.h:157
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
char elem_index_dirty
Definition: bmesh_class.h:305
struct BMEditMesh * edit_mesh
void * data
uint side_was_swapped
Definition: uvedit_rip.c:97
uint in_rip_pairs
Definition: uvedit_rip.c:89
uint is_select_vert_single
Definition: uvedit_rip.c:83
uint in_stack
Definition: uvedit_rip.c:87
uint is_select_edge
Definition: uvedit_rip.c:70
uint side
Definition: uvedit_rip.c:91
uint is_select_all
Definition: uvedit_rip.c:85
GSet * loops
Definition: uvedit_rip.c:448
GSet * loops
Definition: uvedit_rip.c:296
int mval[2]
Definition: WM_types.h:583
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
struct PointerRNA * ptr
void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit)
Definition: uvedit_ops.c:193
struct UVRipPairs UVRipPairs
static int uv_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: uvedit_rip.c:939
static BMLoop * bm_loop_find_other_fan_loop_with_visible_face(BMLoop *l_src, BMVert *v_src, const int cd_loop_uv_offset)
Definition: uvedit_rip.c:138
#define UV_SET_SIDE_AND_REMOVE_FROM_RAIL(loop, side_value)
static void bm_loop_uv_select_single_vert_validate(BMLoop *l_init, const int cd_loop_uv_offset)
Definition: uvedit_rip.c:201
static void uv_rip_pairs_free(UVRipPairs *rip)
Definition: uvedit_rip.c:686
static void uv_rip_single_free(UVRipSingle *rip)
Definition: uvedit_rip.c:434
static int uv_rip_exec(bContext *C, wmOperator *op)
Definition: uvedit_rip.c:897
static void uv_rip_pairs_remove(UVRipPairs *rip, BMLoop *l)
Definition: uvedit_rip.c:460
static void uv_rip_pairs_add(UVRipPairs *rip, BMLoop *l)
Definition: uvedit_rip.c:451
static int uv_rip_pairs_loop_count_on_side(BMLoop *l_init, uint side, const int cd_loop_uv_offset)
Definition: uvedit_rip.c:505
static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const float aspect_y)
Definition: uvedit_rip.c:747
void UV_OT_rip(wmOperatorType *ot)
Definition: uvedit_rip.c:950
static UVRipSingle * uv_rip_single_from_loop(BMLoop *l_init_orig, const float co[2], const float aspect_y, const int cd_loop_uv_offset)
Definition: uvedit_rip.c:313
static float uv_rip_pairs_calc_uv_angle(BMLoop *l_init, uint side, const float aspect_y, const int cd_loop_uv_offset)
Definition: uvedit_rip.c:473
BLI_STATIC_ASSERT(sizeof(ULData)<=sizeof(int), "")
static bool uv_rip_pairs_calc_center_and_direction(UVRipPairs *rip, const int cd_loop_uv_offset, float r_center[2], float r_dir_side[2][2])
Definition: uvedit_rip.c:695
static BMLoop * bm_vert_step_fan_loop_uv(BMLoop *l, BMEdge **e_step, const int cd_loop_uv_offset)
Definition: uvedit_rip.c:181
static bool uv_rip_pairs_loop_change_sides_test(BMLoop *l_switch, BMLoop *l_target, const float aspect_y, const int cd_loop_uv_offset)
Definition: uvedit_rip.c:524
static UVRipPairs * uv_rip_pairs_from_loop(BMLoop *l_init, const float aspect_y, const int cd_loop_uv_offset)
Definition: uvedit_rip.c:567
struct UVRipSingle UVRipSingle
struct ULData ULData
static void bm_loop_calc_uv_angle_from_dir(BMLoop *l, const float dir[2], const float aspect_y, const int cd_loop_uv_offset, float *r_corner_angle, float *r_edge_angle, int *r_edge_index)
Definition: uvedit_rip.c:234
static BMLoop * bm_loop_find_other_radial_loop_with_visible_face(BMLoop *l_src, const int cd_loop_uv_offset)
Definition: uvedit_rip.c:114
BLI_INLINE ULData * UL(BMLoop *l)
Definition: uvedit_rip.c:103
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156