Blender  V3.3
uvedit_select.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include <math.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "DNA_image_types.h"
15 #include "DNA_material_types.h"
16 #include "DNA_meshdata_types.h"
17 #include "DNA_node_types.h"
18 #include "DNA_object_types.h"
19 #include "DNA_scene_types.h"
20 #include "DNA_space_types.h"
21 
22 #include "BLI_alloca.h"
23 #include "BLI_blenlib.h"
24 #include "BLI_hash.h"
25 #include "BLI_kdopbvh.h"
26 #include "BLI_kdtree.h"
27 #include "BLI_lasso_2d.h"
28 #include "BLI_math.h"
29 #include "BLI_polyfill_2d.h"
30 #include "BLI_utildefines.h"
31 
32 #include "BKE_context.h"
33 #include "BKE_customdata.h"
34 #include "BKE_editmesh.h"
35 #include "BKE_layer.h"
36 #include "BKE_material.h"
37 #include "BKE_mesh.h"
38 #include "BKE_mesh_mapping.h"
39 #include "BKE_report.h"
40 
41 #include "DEG_depsgraph.h"
42 #include "DEG_depsgraph_query.h"
43 
44 #include "ED_image.h"
45 #include "ED_mesh.h"
46 #include "ED_screen.h"
47 #include "ED_select_utils.h"
48 #include "ED_uvedit.h"
49 
50 #include "RNA_access.h"
51 #include "RNA_define.h"
52 #include "RNA_enum_types.h"
53 
54 #include "WM_api.h"
55 #include "WM_types.h"
56 
57 #include "UI_view2d.h"
58 
59 #include "uvedit_intern.h"
60 
61 static void uv_select_all_perform(const Scene *scene, Object *obedit, int action);
62 
63 static void uv_select_all_perform_multi_ex(const Scene *scene,
64  Object **objects,
65  const uint objects_len,
66  int action,
67  const Object *ob_exclude);
68 static void uv_select_all_perform_multi(const Scene *scene,
69  Object **objects,
70  const uint objects_len,
71  int action);
72 
73 static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, const bool select);
74 static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, const bool select);
76 
78  const ToolSettings *ts,
79  Object *obedit);
80 
81 typedef enum {
90 
91 /* -------------------------------------------------------------------- */
99 {
105 }
106 
108 {
110  if (ese && ese->prev) {
111  BMEditSelection *ese_prev = ese->prev;
112  if ((ese->htype == BM_VERT) && (ese_prev->htype == BM_FACE)) {
113  /* May be NULL. */
114  return BM_face_vert_share_loop((BMFace *)ese_prev->ele, (BMVert *)ese->ele);
115  }
116  }
117  return NULL;
118 }
119 
121 {
127 }
128 
130 {
132  if (ese && ese->prev) {
133  BMEditSelection *ese_prev = ese->prev;
134  if ((ese->htype == BM_EDGE) && (ese_prev->htype == BM_FACE)) {
135  /* May be NULL. */
136  return BM_face_edge_share_loop((BMFace *)ese_prev->ele, (BMEdge *)ese->ele);
137  }
138  }
139  return NULL;
140 }
141 
144 /* -------------------------------------------------------------------- */
149 {
150  const ToolSettings *ts = scene->toolsettings;
151  char uv_selectmode = UV_SELECT_VERTEX;
152 
153  if (ts->uv_flag & UV_SYNC_SELECTION) {
154  if (ts->selectmode & SCE_SELECT_VERTEX) {
155  uv_selectmode = UV_SELECT_VERTEX;
156  }
157  else if (ts->selectmode & SCE_SELECT_EDGE) {
158  uv_selectmode = UV_SELECT_EDGE;
159  }
160  else if (ts->selectmode & SCE_SELECT_FACE) {
161  uv_selectmode = UV_SELECT_FACE;
162  }
163  }
164  else {
165  if (ts->uv_selectmode & UV_SELECT_VERTEX) {
166  uv_selectmode = UV_SELECT_VERTEX;
167  }
168  else if (ts->uv_selectmode & UV_SELECT_EDGE) {
169  uv_selectmode = UV_SELECT_EDGE;
170  }
171  else if (ts->uv_selectmode & UV_SELECT_FACE) {
172  uv_selectmode = UV_SELECT_FACE;
173  }
174  }
175  return uv_selectmode;
176 }
177 
179 {
180  /* bmesh API handles flushing but not on de-select */
181  if (ts->uv_flag & UV_SYNC_SELECTION) {
182  if (ts->selectmode != SCE_SELECT_FACE) {
183  if (select == false) {
185  }
186  else {
187  EDBM_select_flush(em);
188  }
189  }
190 
191  if (select == false) {
193  }
194  }
195 }
196 
198  Scene *scene,
199  bool select,
200  int cd_loop_uv_offset)
201 {
202  BMFace *efa;
203  BMLoop *l;
204  BMIter iter, liter;
205 
206  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
207  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
208  if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
209  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
210  }
211  }
212  }
213 }
214 
216 {
217  if (ts->uv_flag & UV_SYNC_SELECTION) {
218  return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
219  }
221 }
223 {
225 }
226 
227 bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
228 {
229  if (ts->uv_flag & UV_SYNC_SELECTION) {
230  return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
231  }
232 
233  BMLoop *l;
234  MLoopUV *luv;
235  BMIter liter;
236 
237  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
238  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
239  if (ts->uv_selectmode & UV_SELECT_VERTEX) {
240  if ((luv->flag & MLOOPUV_VERTSEL) == 0) {
241  return false;
242  }
243  }
244  else {
245  if ((luv->flag & MLOOPUV_EDGESEL) == 0) {
246  return false;
247  }
248  }
249  }
250  return true;
251 }
252 bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
253 {
254  return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
255 }
256 
258  BMEditMesh *em,
259  BMFace *efa,
260  const bool select,
261  const bool do_history,
262  const int cd_loop_uv_offset)
263 {
264  const ToolSettings *ts = scene->toolsettings;
265  const char sticky = ts->uv_sticky;
266  if (ts->uv_flag & UV_SYNC_SELECTION) {
267  uvedit_face_select_set(scene, em, efa, select, do_history, cd_loop_uv_offset);
268  return;
269  }
270  if (!uvedit_face_visible_test(scene, efa)) {
271  return;
272  }
273  /* NOTE: Previously face selections done in sticky vertex mode selected stray UV vertices
274  * (not part of any face selections). This now uses the sticky location mode logic instead. */
275  switch (sticky) {
276  case SI_STICKY_DISABLE: {
277  uvedit_face_select_set(scene, em, efa, select, do_history, cd_loop_uv_offset);
278  break;
279  }
280  default: {
281  /* SI_STICKY_LOC and SI_STICKY_VERTEX modes. */
282  uvedit_face_select_shared_vert(scene, em, efa, select, do_history, cd_loop_uv_offset);
283  }
284  }
285 }
286 
288  BMEditMesh *em,
289  BMFace *efa,
290  const bool select,
291  const bool do_history,
292  const int cd_loop_uv_offset)
293 {
294  BMLoop *l;
295  BMIter liter;
296 
297  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
298  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
299  if (select) {
300  luv->flag |= MLOOPUV_EDGESEL;
302  scene, em, l, select, SI_STICKY_LOC, do_history, cd_loop_uv_offset);
303  }
304  else {
305  luv->flag &= ~MLOOPUV_EDGESEL;
306  if (!uvedit_vert_is_face_select_any_other(scene, l, cd_loop_uv_offset)) {
308  scene, em, l, select, SI_STICKY_LOC, do_history, cd_loop_uv_offset);
309  }
310  }
311  }
312 }
313 
315  BMEditMesh *em,
316  BMFace *efa,
317  const bool select,
318  const bool do_history,
319  const int cd_loop_uv_offset)
320 {
321  if (select) {
322  uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
323  }
324  else {
325  uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
326  }
327 }
328 
330  BMEditMesh *em,
331  BMFace *efa,
332  const bool do_history,
333  const int cd_loop_uv_offset)
334 {
335  const ToolSettings *ts = scene->toolsettings;
336 
337  if (ts->uv_flag & UV_SYNC_SELECTION) {
338  BM_face_select_set(em->bm, efa, true);
339  if (do_history) {
340  BM_select_history_store(em->bm, (BMElem *)efa);
341  }
342  }
343  else {
344  BMLoop *l;
345  MLoopUV *luv;
346  BMIter liter;
347 
348  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
349  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
351  }
352  }
353 }
354 
356  BMEditMesh *em,
357  BMFace *efa,
358  const int cd_loop_uv_offset)
359 {
360  const ToolSettings *ts = scene->toolsettings;
361 
362  if (ts->uv_flag & UV_SYNC_SELECTION) {
363  BM_face_select_set(em->bm, efa, false);
364  }
365  else {
366  BMLoop *l;
367  MLoopUV *luv;
368  BMIter liter;
369 
370  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
371  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
372  luv->flag &= ~(MLOOPUV_VERTSEL | MLOOPUV_EDGESEL);
373  }
374  }
375 }
376 
377 bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
378 {
379  if (ts->uv_flag & UV_SYNC_SELECTION) {
380  if (ts->selectmode & SCE_SELECT_FACE) {
382  }
383  if (ts->selectmode == SCE_SELECT_EDGE) {
385  }
386  return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
388  }
389 
390  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
391 
392  if (ts->uv_selectmode & UV_SELECT_VERTEX) {
393  MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
394  return (luv->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL);
395  }
396  return (luv->flag & MLOOPUV_EDGESEL);
397 }
398 
399 bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
400 {
401  return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
402 }
403 
405  BMEditMesh *em,
406  BMLoop *l,
407  const bool select,
408  const bool do_history,
409  const uint cd_loop_uv_offset)
410 {
411  const ToolSettings *ts = scene->toolsettings;
412  if (ts->uv_flag & UV_SYNC_SELECTION) {
413  uvedit_edge_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
414  return;
415  }
416 
417  const int sticky = ts->uv_sticky;
418  switch (sticky) {
419  case SI_STICKY_DISABLE: {
421  uvedit_edge_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
422  }
423  break;
424  }
425  case SI_STICKY_VERTEX: {
427  scene, em, l, select, SI_STICKY_VERTEX, do_history, cd_loop_uv_offset);
428  break;
429  }
430  default: {
431  /* SI_STICKY_LOC (Fallback) */
433  scene, em, l, select, SI_STICKY_LOC, do_history, cd_loop_uv_offset);
434  break;
435  }
436  }
437 }
438 
447  BMEditMesh *em,
448  BMLoop *l,
449  const bool select,
450  const int sticky_flag,
451  const bool do_history,
452  const int cd_loop_uv_offset)
453 {
455  /* Set edge flags. Rely on this for face visibility checks */
456  uvedit_edge_select_set_noflush(scene, l, select, sticky_flag, cd_loop_uv_offset);
457 
458  /* Vert selections. */
459  BMLoop *l_iter = l;
460  do {
461  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
462  if (select && (luv->flag & MLOOPUV_EDGESEL)) {
464  scene, em, l_iter, true, SI_STICKY_LOC, do_history, cd_loop_uv_offset);
466  scene, em, l_iter->next, true, SI_STICKY_LOC, do_history, cd_loop_uv_offset);
467  }
468 
469  else if (!select && !(luv->flag & MLOOPUV_EDGESEL)) {
470  if (!uvedit_vert_is_edge_select_any_other(scene, l, cd_loop_uv_offset)) {
472  scene, em, l_iter, false, SI_STICKY_LOC, do_history, cd_loop_uv_offset);
473  }
474  if (!uvedit_vert_is_edge_select_any_other(scene, l->next, cd_loop_uv_offset)) {
476  scene, em, l_iter->next, false, SI_STICKY_LOC, do_history, cd_loop_uv_offset);
477  }
478  }
479  } while (((l_iter = l_iter->radial_next) != l) && (sticky_flag != SI_STICKY_LOC));
480 }
481 
482 /* Set edge flags for required UV edges. */
484  BMLoop *l,
485  const bool select,
486  const int sticky_flag,
487  const int cd_loop_uv_offset)
488 {
489  MLoopUV *luv;
490  BMLoop *l_iter = l;
491  do {
492  if (uvedit_face_visible_test(scene, l_iter->f)) {
493  if ((sticky_flag == SI_STICKY_VERTEX) ||
494  BM_loop_uv_share_edge_check(l, l_iter, cd_loop_uv_offset)) {
495  luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
497  }
498  }
499  } while (((l_iter = l_iter->radial_next) != l) && (sticky_flag != SI_STICKY_DISABLE));
500 }
501 
503  BMEditMesh *em,
504  BMLoop *l,
505  const bool select,
506  const bool do_history,
507  const int cd_loop_uv_offset)
508 
509 {
510  if (select) {
511  uvedit_edge_select_enable(scene, em, l, do_history, cd_loop_uv_offset);
512  }
513  else {
514  uvedit_edge_select_disable(scene, em, l, cd_loop_uv_offset);
515  }
516 }
517 
519  BMEditMesh *em,
520  BMLoop *l,
521  const bool do_history,
522  const int cd_loop_uv_offset)
523 
524 {
525  const ToolSettings *ts = scene->toolsettings;
526 
527  if (ts->uv_flag & UV_SYNC_SELECTION) {
528  if (ts->selectmode & SCE_SELECT_FACE) {
529  BM_face_select_set(em->bm, l->f, true);
530  }
531  else if (ts->selectmode & SCE_SELECT_EDGE) {
532  BM_edge_select_set(em->bm, l->e, true);
533  }
534  else {
535  BM_vert_select_set(em->bm, l->e->v1, true);
536  BM_vert_select_set(em->bm, l->e->v2, true);
537  }
538 
539  if (do_history) {
540  BM_select_history_store(em->bm, (BMElem *)l->e);
541  }
542  }
543  else {
544  MLoopUV *luv, *luv_next;
545  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
546  luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
547 
549  luv_next->flag |= MLOOPUV_VERTSEL;
550  }
551 }
552 
554  BMEditMesh *em,
555  BMLoop *l,
556  const int cd_loop_uv_offset)
557 
558 {
559  const ToolSettings *ts = scene->toolsettings;
560 
561  if (ts->uv_flag & UV_SYNC_SELECTION) {
562  if (ts->selectmode & SCE_SELECT_FACE) {
563  BM_face_select_set(em->bm, l->f, false);
564  }
565  else if (ts->selectmode & SCE_SELECT_EDGE) {
566  BM_edge_select_set(em->bm, l->e, false);
567  }
568  else {
569  BM_vert_select_set(em->bm, l->e->v1, false);
570  BM_vert_select_set(em->bm, l->e->v2, false);
571  }
572  }
573  else {
574  MLoopUV *luv, *luv_next;
575  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
576  luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
577 
578  luv->flag &= ~MLOOPUV_EDGESEL;
579  if ((ts->uv_selectmode & UV_SELECT_VERTEX) == 0) {
580  /* Deselect UV vertex if not part of another edge selection */
581  MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
582  if (!(luv_next->flag & MLOOPUV_EDGESEL)) {
583  luv_next->flag &= ~MLOOPUV_VERTSEL;
584  }
585  if (!(luv_prev->flag & MLOOPUV_EDGESEL)) {
586  luv->flag &= ~MLOOPUV_VERTSEL;
587  }
588  }
589  else {
590  luv_next->flag &= ~MLOOPUV_VERTSEL;
591  luv->flag &= ~MLOOPUV_VERTSEL;
592  }
593  }
594 }
595 
596 bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
597 {
598  if (ts->uv_flag & UV_SYNC_SELECTION) {
599  if (ts->selectmode & SCE_SELECT_FACE) {
601  }
602  if (ts->selectmode & SCE_SELECT_EDGE) {
603  /* Are you looking for `uvedit_edge_select_test(...)` instead? */
604  }
606  }
607 
608  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
609 
610  if (ts->selectmode & SCE_SELECT_FACE) {
611  /* Are you looking for `uvedit_face_select_test(...)` instead? */
612  }
613 
614  if (ts->selectmode & SCE_SELECT_EDGE) {
615  /* Are you looking for `uvedit_edge_select_test(...)` instead? */
616  }
617 
618  return (luv->flag & MLOOPUV_VERTSEL) != 0;
619 }
620 
621 bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
622 {
623  return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
624 }
625 
627  BMEditMesh *em,
628  BMLoop *l,
629  const bool select,
630  const bool do_history,
631  const uint cd_loop_uv_offset)
632 {
633  const ToolSettings *ts = scene->toolsettings;
634  if (ts->uv_flag & UV_SYNC_SELECTION) {
635  uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
636  return;
637  }
638 
639  const int sticky = ts->uv_sticky;
640  switch (sticky) {
641  case SI_STICKY_DISABLE: {
643  uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
644  }
645  break;
646  }
647  case SI_STICKY_VERTEX: {
649  scene, em, l, select, SI_STICKY_VERTEX, do_history, cd_loop_uv_offset);
650  break;
651  }
652  default: {
653  /* SI_STICKY_LOC. */
655  scene, em, l, select, SI_STICKY_LOC, do_history, cd_loop_uv_offset);
656  break;
657  }
658  }
659 }
660 
669  BMEditMesh *em,
670  BMLoop *l,
671  const bool select,
672  const int sticky_flag,
673  const bool do_history,
674  const int cd_loop_uv_offset)
675 {
677 
678  BMEdge *e_first, *e_iter;
679  e_first = e_iter = l->e;
680  do {
681  BMLoop *l_radial_iter = e_iter->l;
682  if (!l_radial_iter) {
683  continue; /* Skip wire edges with no loops. */
684  }
685  do {
686  if (l_radial_iter->v == l->v) {
687  if (uvedit_face_visible_test(scene, l_radial_iter->f)) {
688  bool do_select = false;
689  if (sticky_flag == SI_STICKY_VERTEX) {
690  do_select = true;
691  }
692  else if (BM_loop_uv_share_vert_check(l, l_radial_iter, cd_loop_uv_offset)) {
693  do_select = true;
694  }
695 
696  if (do_select) {
697  uvedit_uv_select_set(scene, em, l_radial_iter, select, do_history, cd_loop_uv_offset);
698  }
699  }
700  }
701  } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l);
702  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != e_first);
703 }
704 
706  BMEditMesh *em,
707  BMLoop *l,
708  const bool select,
709  const bool do_history,
710  const int cd_loop_uv_offset)
711 {
712  if (select) {
713  uvedit_uv_select_enable(scene, em, l, do_history, cd_loop_uv_offset);
714  }
715  else {
716  uvedit_uv_select_disable(scene, em, l, cd_loop_uv_offset);
717  }
718 }
719 
721  BMEditMesh *em,
722  BMLoop *l,
723  const bool do_history,
724  const int cd_loop_uv_offset)
725 {
726  const ToolSettings *ts = scene->toolsettings;
727 
728  if (ts->selectmode & SCE_SELECT_EDGE) {
729  /* Are you looking for `uvedit_edge_select_set(...)` instead? */
730  }
731 
732  if (ts->uv_flag & UV_SYNC_SELECTION) {
733  if (ts->selectmode & SCE_SELECT_FACE) {
734  BM_face_select_set(em->bm, l->f, true);
735  }
736  else {
737  BM_vert_select_set(em->bm, l->v, true);
738  }
739 
740  if (do_history) {
741  BM_select_history_store(em->bm, (BMElem *)l->v);
742  }
743  }
744  else {
745  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
746  luv->flag |= MLOOPUV_VERTSEL;
747  }
748 }
749 
751  BMEditMesh *em,
752  BMLoop *l,
753  const int cd_loop_uv_offset)
754 {
755  const ToolSettings *ts = scene->toolsettings;
756 
757  if (ts->uv_flag & UV_SYNC_SELECTION) {
758  if (ts->selectmode & SCE_SELECT_FACE) {
759  BM_face_select_set(em->bm, l->f, false);
760  }
761  else {
762  BM_vert_select_set(em->bm, l->v, false);
763  }
764  }
765  else {
766  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
767  luv->flag &= ~MLOOPUV_VERTSEL;
768  }
769 }
770 
772  BMLoop *l_src,
773  const int cd_loop_uv_offset)
774 {
775  BMLoop *l_other = NULL;
776  BMLoop *l_iter = l_src->radial_next;
777  if (l_iter != l_src) {
778  do {
779  if (uvedit_face_visible_test(scene, l_iter->f) &&
780  BM_loop_uv_share_edge_check(l_src, l_iter, cd_loop_uv_offset)) {
781  /* Check UV's are contiguous. */
782  if (l_other == NULL) {
783  l_other = l_iter;
784  }
785  else {
786  /* Only use when there is a single alternative. */
787  l_other = NULL;
788  break;
789  }
790  }
791  } while ((l_iter = l_iter->radial_next) != l_src);
792  }
793  return l_other;
794 }
795 
797  BMLoop *l_edge,
798  BMVert *v_pivot,
799  const int cd_loop_uv_offset)
800 {
802  scene, l_edge, cd_loop_uv_offset) == NULL);
803 
804  BMLoop *l_step = l_edge;
805  l_step = (l_step->v == v_pivot) ? l_step->prev : l_step->next;
806  BMLoop *l_step_last = NULL;
807  do {
808  BLI_assert(BM_vert_in_edge(l_step->e, v_pivot));
809  l_step_last = l_step;
811  scene, l_step, cd_loop_uv_offset);
812  if (l_step) {
813  l_step = (l_step->v == v_pivot) ? l_step->prev : l_step->next;
814  }
815  } while (l_step != NULL);
816 
817  if (l_step_last != NULL) {
819  scene, l_step_last, cd_loop_uv_offset) == NULL);
820  }
821 
822  return l_step_last;
823 }
824 
827 /* -------------------------------------------------------------------- */
832  Scene *scene, Object *obedit, const float co[2], const float penalty, UvNearestHit *hit)
833 {
834  BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f));
835  BMEditMesh *em = BKE_editmesh_from_object(obedit);
836  BMFace *efa;
837  BMLoop *l;
838  BMIter iter, liter;
839  MLoopUV *luv, *luv_next;
840  int i;
841  bool found = false;
842 
843  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
844 
846 
847  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
848  if (!uvedit_face_visible_test(scene, efa)) {
849  continue;
850  }
851  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
852  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
853  luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
854 
855  float delta[2];
856  closest_to_line_segment_v2(delta, co, luv->uv, luv_next->uv);
857 
858  sub_v2_v2(delta, co);
859  mul_v2_v2(delta, hit->scale);
860 
861  float dist_test_sq = len_squared_v2(delta);
862 
863  /* Ensures that successive selection attempts will select other edges sharing the same
864  * UV coordinates as the previous selection. */
865  if ((penalty != 0.0f) && uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
866  dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty);
867  }
868  if (dist_test_sq < hit->dist_sq) {
869  hit->ob = obedit;
870  hit->efa = efa;
871 
872  hit->l = l;
873 
874  hit->dist_sq = dist_test_sq;
875  found = true;
876  }
877  }
878  }
879  return found;
880 }
881 
883  Object **objects,
884  const uint objects_len,
885  const float co[2],
886  const float penalty,
887  UvNearestHit *hit)
888 {
889  bool found = false;
890  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
891  Object *obedit = objects[ob_index];
892  if (uv_find_nearest_edge(scene, obedit, co, penalty, hit)) {
893  found = true;
894  }
895  }
896  return found;
897 }
898 
900  Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face)
901 {
902  BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f));
903  BMEditMesh *em = BKE_editmesh_from_object(obedit);
904  bool found = false;
905 
906  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
907 
908  BMIter iter;
909  BMFace *efa;
910 
911  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
912  if (!uvedit_face_visible_test(scene, efa)) {
913  continue;
914  }
915 
916  float cent[2];
917  BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
918 
919  float delta[2];
920  sub_v2_v2v2(delta, co, cent);
921  mul_v2_v2(delta, hit->scale);
922 
923  const float dist_test_sq = len_squared_v2(delta);
924 
925  if (dist_test_sq < hit->dist_sq) {
926 
927  if (only_in_face) {
928  if (!BM_face_uv_point_inside_test(efa, co, cd_loop_uv_offset)) {
929  continue;
930  }
931  }
932 
933  hit->ob = obedit;
934  hit->efa = efa;
935  hit->dist_sq = dist_test_sq;
936  found = true;
937  }
938  }
939  return found;
940 }
941 
942 bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
943 {
944  return uv_find_nearest_face_ex(scene, obedit, co, hit, false);
945 }
946 
948  Object **objects,
949  const uint objects_len,
950  const float co[2],
951  UvNearestHit *hit,
952  const bool only_in_face)
953 {
954  bool found = false;
955  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
956  Object *obedit = objects[ob_index];
957  if (uv_find_nearest_face_ex(scene, obedit, co, hit, only_in_face)) {
958  found = true;
959  }
960  }
961  return found;
962 }
963 
965  Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit)
966 {
967  return uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, hit, false);
968 }
969 
970 static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
971 {
972  const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
973  const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
974  const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
975 
976  return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
977  (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
978 }
979 
981  Scene *scene, Object *obedit, float const co[2], const float penalty_dist, UvNearestHit *hit)
982 {
983  BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f));
984  bool found = false;
985 
986  BMEditMesh *em = BKE_editmesh_from_object(obedit);
987  BMFace *efa;
988  BMIter iter;
989 
991 
992  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
993 
994  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
995  if (!uvedit_face_visible_test(scene, efa)) {
996  continue;
997  }
998 
999  BMIter liter;
1000  BMLoop *l;
1001  int i;
1002  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1003  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1004 
1005  float delta[2];
1006 
1007  sub_v2_v2v2(delta, co, luv->uv);
1008  mul_v2_v2(delta, hit->scale);
1009 
1010  float dist_test_sq = len_squared_v2(delta);
1011 
1012  /* Ensures that successive selection attempts will select other vertices sharing the same
1013  * UV coordinates */
1014  if ((penalty_dist != 0.0f) && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1015  dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty_dist);
1016  }
1017 
1018  if (dist_test_sq <= hit->dist_sq) {
1019  if (dist_test_sq == hit->dist_sq) {
1020  if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
1021  continue;
1022  }
1023  }
1024 
1025  hit->dist_sq = dist_test_sq;
1026 
1027  hit->ob = obedit;
1028  hit->efa = efa;
1029  hit->l = l;
1030  found = true;
1031  }
1032  }
1033  }
1034 
1035  return found;
1036 }
1037 
1039  Object **objects,
1040  const uint objects_len,
1041  float const co[2],
1042  const float penalty_dist,
1043  UvNearestHit *hit)
1044 {
1045  bool found = false;
1046  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1047  Object *obedit = objects[ob_index];
1048  if (uv_find_nearest_vert(scene, obedit, co, penalty_dist, hit)) {
1049  found = true;
1050  }
1051  }
1052  return found;
1053 }
1054 
1055 static bool uvedit_nearest_uv(const Scene *scene,
1056  Object *obedit,
1057  const float co[2],
1058  const float scale[2],
1059  const bool ignore_selected,
1060  float *dist_sq,
1061  float r_uv[2])
1062 {
1063  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1064  BMIter iter;
1065  BMFace *efa;
1066  const float *uv_best = NULL;
1067  float dist_best = *dist_sq;
1068  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1069  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1070  if (!uvedit_face_visible_test(scene, efa)) {
1071  continue;
1072  }
1073  BMLoop *l_iter, *l_first;
1074  l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
1075  do {
1076  if (ignore_selected && uvedit_uv_select_test(scene, l_iter, cd_loop_uv_offset)) {
1077  continue;
1078  }
1079 
1080  const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
1081  float co_tmp[2];
1082  mul_v2_v2v2(co_tmp, scale, uv);
1083  const float dist_test = len_squared_v2v2(co, co_tmp);
1084  if (dist_best > dist_test) {
1085  dist_best = dist_test;
1086  uv_best = uv;
1087  }
1088  } while ((l_iter = l_iter->next) != l_first);
1089  }
1090 
1091  if (uv_best != NULL) {
1092  copy_v2_v2(r_uv, uv_best);
1093  *dist_sq = dist_best;
1094  return true;
1095  }
1096  return false;
1097 }
1098 
1100  const Scene *scene,
1101  Object **objects,
1102  const uint objects_len,
1103  const int mval[2],
1104  const bool ignore_selected,
1105  float *dist_sq,
1106  float r_uv[2])
1107 {
1108  bool found = false;
1109 
1110  float scale[2], offset[2];
1111  UI_view2d_scale_get(v2d, &scale[0], &scale[1]);
1112  UI_view2d_view_to_region_fl(v2d, 0.0f, 0.0f, &offset[0], &offset[1]);
1113 
1114  float co[2];
1115  sub_v2_v2v2(co, (float[2]){UNPACK2(mval)}, offset);
1116 
1117  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1118  Object *obedit = objects[ob_index];
1119  if (uvedit_nearest_uv(scene, obedit, co, scale, ignore_selected, dist_sq, r_uv)) {
1120  found = true;
1121  }
1122  }
1123  return found;
1124 }
1125 
1128 /* -------------------------------------------------------------------- */
1137  struct Object *obedit,
1138  struct BMVert *v,
1139  const float co[2])
1140 {
1141  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1142  const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1143 
1144  BMIter liter;
1145  BMLoop *l;
1146  BMLoop *l_found = NULL;
1147  float dist_best_sq = FLT_MAX;
1148 
1149  BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
1150  if (!uvedit_face_visible_test(scene, l->f)) {
1151  continue;
1152  }
1153 
1154  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1155  const float dist_test_sq = len_squared_v2v2(co, luv->uv);
1156  if (dist_test_sq < dist_best_sq) {
1157  dist_best_sq = dist_test_sq;
1158  l_found = l;
1159  }
1160  }
1161  return l_found;
1162 }
1163 
1165  struct Object *obedit,
1166  struct BMEdge *e,
1167  const float co[2])
1168 {
1169  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1170  const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1171 
1172  BMIter eiter;
1173  BMLoop *l;
1174  BMLoop *l_found = NULL;
1175  float dist_best_sq = FLT_MAX;
1176 
1177  BM_ITER_ELEM (l, &eiter, e, BM_LOOPS_OF_EDGE) {
1178  if (!uvedit_face_visible_test(scene, l->f)) {
1179  continue;
1180  }
1181  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1182  const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
1183  const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
1184  if (dist_test_sq < dist_best_sq) {
1185  dist_best_sq = dist_test_sq;
1186  l_found = l;
1187  }
1188  }
1189  return l_found;
1190 }
1191 
1194 /* -------------------------------------------------------------------- */
1199  BMLoop *l,
1200  const int cd_loop_uv_offset)
1201 {
1202  BMEdge *e_iter = l->e;
1203  do {
1204  BMLoop *l_radial_iter = e_iter->l, *l_other;
1205  do {
1206  if (uvedit_face_visible_test(scene, l_radial_iter->f)) {
1207  /* Use #l_other to check if the uvs are connected (share the same uv coordinates)
1208  * and #l_radial_iter for the actual edge selection test. */
1209  l_other = (l_radial_iter->v != l->v) ? l_radial_iter->next : l_radial_iter;
1210  if (BM_loop_uv_share_vert_check(l, l_other, cd_loop_uv_offset) &&
1211  uvedit_edge_select_test(scene, l_radial_iter, cd_loop_uv_offset)) {
1212  return true;
1213  }
1214  }
1215  } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l);
1216  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != l->e);
1217 
1218  return false;
1219 }
1220 
1222  BMLoop *l,
1223  const int cd_loop_uv_offset)
1224 {
1225  BMIter liter;
1226  BMLoop *l_iter;
1227  BM_ITER_ELEM (l_iter, &liter, l->v, BM_LOOPS_OF_VERT) {
1228  if (!uvedit_face_visible_test(scene, l_iter->f) || (l_iter->f == l->f)) {
1229  continue;
1230  }
1231  if (BM_loop_uv_share_vert_check(l, l_iter, cd_loop_uv_offset) &&
1232  uvedit_face_select_test(scene, l_iter->f, cd_loop_uv_offset)) {
1233  return true;
1234  }
1235  }
1236  return false;
1237 }
1238 
1240  BMLoop *l,
1241  const int cd_loop_uv_offset)
1242 {
1243  BMIter liter;
1244  BMLoop *l_iter;
1245  BM_ITER_ELEM (l_iter, &liter, l->v, BM_LOOPS_OF_VERT) {
1246  if (!uvedit_face_visible_test(scene, l_iter->f) || (l_iter->f == l->f)) {
1247  continue;
1248  }
1249  if (BM_loop_uv_share_vert_check(l, l_iter, cd_loop_uv_offset) &&
1250  !uvedit_face_select_test(scene, l_iter->f, cd_loop_uv_offset)) {
1251  return false;
1252  }
1253  }
1254  return true;
1255 }
1256 
1260 static void bm_uv_flag_clear(const Scene *scene,
1261  BMesh *bm,
1262  const int flag,
1263  const int cd_loop_uv_offset)
1264 {
1265  BMFace *efa;
1266  BMLoop *l;
1267  BMIter iter, liter;
1268  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1269  if (!uvedit_face_visible_test(scene, efa)) {
1270  continue;
1271  }
1272  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1273  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1274  luv->flag &= ~flag;
1275  }
1276  }
1277 }
1278 
1281 /* -------------------------------------------------------------------- */
1287 {
1288  const ToolSettings *ts = scene->toolsettings;
1289  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1290 
1291  BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0);
1292  UNUSED_VARS_NDEBUG(ts);
1293 
1294  /* Vertex Mode only. */
1295  if (ts->uv_selectmode & UV_SELECT_VERTEX) {
1296  BMFace *efa;
1297  BMLoop *l;
1298  BMIter iter, liter;
1299  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1300  if (!uvedit_face_visible_test(scene, efa)) {
1301  continue;
1302  }
1303  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1304  MLoopUV *luv, *luv_next;
1305  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1306  luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
1307 
1308  if ((luv->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL)) {
1309  luv->flag |= MLOOPUV_EDGESEL;
1310  }
1311  else {
1312  luv->flag &= ~MLOOPUV_EDGESEL;
1313  }
1314  }
1315  }
1316  }
1317 }
1318 
1321 /* -------------------------------------------------------------------- */
1326 {
1327  /* Careful when using this in face select mode.
1328  * For face selections with sticky mode enabled, this can create invalid selection states. */
1329  const ToolSettings *ts = scene->toolsettings;
1330  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1331 
1332  BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0);
1333  UNUSED_VARS_NDEBUG(ts);
1334 
1335  BMFace *efa;
1336  BMLoop *l;
1337  BMIter iter, liter;
1338  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1339  if (!uvedit_face_visible_test(scene, efa)) {
1340  continue;
1341  }
1342  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1343  MLoopUV *luv, *luv_next;
1344  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1345  luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
1346 
1347  if ((luv->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL)) {
1348  luv->flag |= MLOOPUV_EDGESEL;
1349  }
1350  }
1351  }
1352 }
1353 
1355 {
1356  const ToolSettings *ts = scene->toolsettings;
1357  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1358 
1359  BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0);
1360  UNUSED_VARS_NDEBUG(ts);
1361 
1362  BMFace *efa;
1363  BMLoop *l;
1364  BMIter iter, liter;
1365  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1366  if (!uvedit_face_visible_test(scene, efa)) {
1367  continue;
1368  }
1369  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1370  MLoopUV *luv, *luv_next;
1371  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1372  luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
1373 
1374  if (luv->flag & MLOOPUV_EDGESEL) {
1375  if (!(luv->flag & MLOOPUV_VERTSEL) || !(luv_next->flag & MLOOPUV_VERTSEL)) {
1376  luv->flag &= ~MLOOPUV_EDGESEL;
1377  }
1378  }
1379  }
1380  }
1381 }
1382 
1385 /* -------------------------------------------------------------------- */
1395 };
1396 
1398  BMLoop *l_step,
1399  BMVert *v_from,
1400  const int cd_loop_uv_offset)
1401 {
1402  if (l_step->f->len == 4) {
1403  BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from);
1404  BMLoop *l_step_over = (v_from == l_step->v) ? l_step->next : l_step->prev;
1406  scene, l_step_over, cd_loop_uv_offset);
1407  if (l_step_over) {
1408  return (l_step_over->v == v_from_next) ? l_step_over->prev : l_step_over->next;
1409  }
1410  }
1411  return NULL;
1412 }
1413 
1415  BMLoop *l_step,
1416  BMVert *v_from,
1417  const int cd_loop_uv_offset)
1418 {
1419  BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from);
1421  scene, l_step, v_from_next, cd_loop_uv_offset);
1422 }
1423 
1424 /* TODO(campbell): support this in the BMesh API, as we have for clearing other types. */
1426 {
1427  BMIter iter;
1428  BMFace *f;
1429  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1430  BMIter liter;
1431  BMLoop *l_iter;
1432  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
1434  }
1435  }
1436 }
1437 
1442  BMEditMesh *em,
1443  BMLoop *l_init_pair[2],
1444  const int cd_loop_uv_offset)
1445 {
1446  bm_loop_tags_clear(em->bm);
1447 
1448  for (int side = 0; side < 2; side++) {
1449  BMLoop *l_step_pair[2] = {l_init_pair[0], l_init_pair[1]};
1450  BMVert *v_from = side ? l_step_pair[0]->e->v1 : l_step_pair[0]->e->v2;
1451  /* Disable since we start from the same edge. */
1452  BM_elem_flag_disable(l_step_pair[0], BM_ELEM_TAG);
1453  BM_elem_flag_disable(l_step_pair[1], BM_ELEM_TAG);
1454  while ((l_step_pair[0] != NULL) && (l_step_pair[1] != NULL)) {
1455  if (!uvedit_face_visible_test(scene, l_step_pair[0]->f) ||
1456  !uvedit_face_visible_test(scene, l_step_pair[1]->f) ||
1457  /* Check loops have not diverged. */
1459  scene, l_step_pair[0], cd_loop_uv_offset) != l_step_pair[1])) {
1460  break;
1461  }
1462 
1463  BLI_assert(l_step_pair[0]->e == l_step_pair[1]->e);
1464 
1465  BM_elem_flag_enable(l_step_pair[0], BM_ELEM_TAG);
1466  BM_elem_flag_enable(l_step_pair[1], BM_ELEM_TAG);
1467 
1468  BMVert *v_from_next = BM_edge_other_vert(l_step_pair[0]->e, v_from);
1469  /* Walk over both sides, ensure they keep on the same edge. */
1470  for (int i = 0; i < ARRAY_SIZE(l_step_pair); i++) {
1471  l_step_pair[i] = bm_select_edgeloop_double_side_next(
1472  scene, l_step_pair[i], v_from, cd_loop_uv_offset);
1473  }
1474 
1475  if ((l_step_pair[0] && BM_elem_flag_test(l_step_pair[0], BM_ELEM_TAG)) ||
1476  (l_step_pair[1] && BM_elem_flag_test(l_step_pair[1], BM_ELEM_TAG))) {
1477  break;
1478  }
1479  v_from = v_from_next;
1480  }
1481  }
1482 }
1483 
1491  BMEditMesh *em,
1492  BMLoop *l_init,
1493  const int cd_loop_uv_offset,
1494  enum eUVEdgeLoopBoundaryMode boundary_mode,
1495  int r_count_by_select[2])
1496 {
1497  if (r_count_by_select) {
1498  r_count_by_select[0] = r_count_by_select[1] = 0;
1499  }
1500 
1501  bm_loop_tags_clear(em->bm);
1502 
1503  for (int side = 0; side < 2; side++) {
1504  BMLoop *l_step = l_init;
1505  BMVert *v_from = side ? l_step->e->v1 : l_step->e->v2;
1506  /* Disable since we start from the same edge. */
1508  while (l_step != NULL) {
1509 
1510  if (!uvedit_face_visible_test(scene, l_step->f) ||
1511  /* Check the boundary is still a boundary. */
1513  scene, l_step, cd_loop_uv_offset) != NULL)) {
1514  break;
1515  }
1516 
1517  if (r_count_by_select != NULL) {
1518  r_count_by_select[uvedit_edge_select_test(scene, l_step, cd_loop_uv_offset)] += 1;
1519  /* Early exit when mixed could be optional if needed. */
1520  if (r_count_by_select[0] && r_count_by_select[1]) {
1521  r_count_by_select[0] = r_count_by_select[1] = -1;
1522  break;
1523  }
1524  }
1525 
1527 
1528  BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from);
1529  BMFace *f_step_prev = l_step->f;
1530 
1531  l_step = bm_select_edgeloop_single_side_next(scene, l_step, v_from, cd_loop_uv_offset);
1532 
1533  if (l_step && BM_elem_flag_test(l_step, BM_ELEM_TAG)) {
1534  break;
1535  }
1536  if (boundary_mode == UV_EDGE_LOOP_BOUNDARY_LOOP) {
1537  /* Don't allow walking over the face. */
1538  if (f_step_prev == l_step->f) {
1539  break;
1540  }
1541  }
1542  v_from = v_from_next;
1543  }
1544  }
1545 }
1546 
1547 static int uv_select_edgeloop(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
1548 {
1549  const ToolSettings *ts = scene->toolsettings;
1550  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1551  bool select;
1552 
1553  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1554 
1555  if (extend) {
1556  select = !(uvedit_edge_select_test(scene, hit->l, cd_loop_uv_offset));
1557  }
1558  else {
1559  select = true;
1560  }
1561 
1562  BMLoop *l_init_pair[2] = {
1563  hit->l,
1565  };
1566 
1567  /* When selecting boundaries, support cycling between selection modes. */
1569 
1570  /* Tag all loops that are part of the edge loop (select after).
1571  * This is done so we can */
1572  if (l_init_pair[1] == NULL) {
1573  int count_by_select[2];
1574  /* If the loops selected toggle the boundaries. */
1576  scene, em, l_init_pair[0], cd_loop_uv_offset, boundary_mode, count_by_select);
1577  if (count_by_select[!select] == 0) {
1578  boundary_mode = UV_EDGE_LOOP_BOUNDARY_ALL;
1579 
1580  /* If the boundary is selected, toggle back to the loop. */
1582  scene, em, l_init_pair[0], cd_loop_uv_offset, boundary_mode, count_by_select);
1583  if (count_by_select[!select] == 0) {
1584  boundary_mode = UV_EDGE_LOOP_BOUNDARY_LOOP;
1585  }
1586  }
1587  }
1588 
1589  if (l_init_pair[1] == NULL) {
1591  scene, em, l_init_pair[0], cd_loop_uv_offset, boundary_mode, NULL);
1592  }
1593  else {
1594  uv_select_edgeloop_double_side_tag(scene, em, l_init_pair, cd_loop_uv_offset);
1595  }
1596 
1597  /* Apply the selection. */
1598  if (!extend) {
1600  }
1601 
1602  /* Select all tagged loops. */
1603  {
1604  BMIter iter;
1605  BMFace *f;
1606  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
1607  BMIter liter;
1608  BMLoop *l_iter;
1609  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
1610  if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
1611  if (ts->uv_selectmode == UV_SELECT_VERTEX) {
1612  uvedit_uv_select_set_with_sticky(scene, em, l_iter, select, false, cd_loop_uv_offset);
1614  scene, em, l_iter->next, select, false, cd_loop_uv_offset);
1615  }
1616  else {
1618  scene, em, l_iter, select, false, cd_loop_uv_offset);
1619  }
1620  }
1621  }
1622  }
1623  }
1624 
1625  return (select) ? 1 : -1;
1626 }
1627 
1630 /* -------------------------------------------------------------------- */
1634 static int uv_select_faceloop(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
1635 {
1636  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1637  bool select;
1638 
1639  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1640 
1641  if (!extend) {
1643  }
1644 
1646 
1647  if (extend) {
1648  select = !(uvedit_face_select_test(scene, hit->l->f, cd_loop_uv_offset));
1649  }
1650  else {
1651  select = true;
1652  }
1653 
1654  BMLoop *l_pair[2] = {
1655  hit->l,
1657  };
1658 
1659  for (int side = 0; side < 2; side++) {
1660  BMLoop *l_step = l_pair[side];
1661  while (l_step) {
1662  if (!uvedit_face_visible_test(scene, l_step->f)) {
1663  break;
1664  }
1665 
1666  uvedit_face_select_set_with_sticky(scene, em, l_step->f, select, false, cd_loop_uv_offset);
1667 
1668  BM_elem_flag_enable(l_step->f, BM_ELEM_TAG);
1669  if (l_step->f->len == 4) {
1670  BMLoop *l_step_opposite = l_step->next->next;
1672  scene, l_step_opposite, cd_loop_uv_offset);
1673  }
1674  else {
1675  l_step = NULL;
1676  }
1677 
1678  /* Break iteration when `l_step`:
1679  * - is the first loop where we started from.
1680  * - tagged using #BM_ELEM_TAG (meaning this loop has been visited in this iteration). */
1681  if (l_step && BM_elem_flag_test(l_step->f, BM_ELEM_TAG)) {
1682  break;
1683  }
1684  }
1685  }
1686 
1687  return (select) ? 1 : -1;
1688 }
1689 
1692 /* -------------------------------------------------------------------- */
1696 static int uv_select_edgering(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
1697 {
1698  const ToolSettings *ts = scene->toolsettings;
1699  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1700  const bool use_face_select = (ts->uv_flag & UV_SYNC_SELECTION) ?
1701  (ts->selectmode & SCE_SELECT_FACE) :
1702  (ts->uv_selectmode & UV_SELECT_FACE);
1703  const bool use_vertex_select = (ts->uv_flag & UV_SYNC_SELECTION) ?
1704  (ts->selectmode & SCE_SELECT_VERTEX) :
1706  bool select;
1707 
1708  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1709 
1710  if (!extend) {
1712  }
1713 
1715 
1716  if (extend) {
1717  select = !(uvedit_edge_select_test(scene, hit->l, cd_loop_uv_offset));
1718  }
1719  else {
1720  select = true;
1721  }
1722 
1723  BMLoop *l_pair[2] = {
1724  hit->l,
1726  };
1727 
1728  for (int side = 0; side < 2; side++) {
1729  BMLoop *l_step = l_pair[side];
1730  /* Disable since we start from the same edge. */
1732  while (l_step) {
1733  if (!uvedit_face_visible_test(scene, l_step->f)) {
1734  break;
1735  }
1736 
1737  if (use_face_select) {
1738  /* While selecting face loops is now done in a separate function #uv_select_faceloop(),
1739  * this check is still kept for edge ring selection, to keep it consistent with how edge
1740  * ring selection works in face mode in the 3D viewport. */
1741  uvedit_face_select_set_with_sticky(scene, em, l_step->f, select, false, cd_loop_uv_offset);
1742  }
1743  else if (use_vertex_select) {
1744  uvedit_uv_select_set_with_sticky(scene, em, l_step, select, false, cd_loop_uv_offset);
1746  scene, em, l_step->next, select, false, cd_loop_uv_offset);
1747  }
1748  else {
1749  /* Edge select mode */
1750  uvedit_edge_select_set_with_sticky(scene, em, l_step, select, false, cd_loop_uv_offset);
1751  }
1752 
1753  BM_elem_flag_enable(l_step->e, BM_ELEM_TAG);
1754  if (l_step->f->len == 4) {
1755  BMLoop *l_step_opposite = l_step->next->next;
1757  scene, l_step_opposite, cd_loop_uv_offset);
1758  if (l_step == NULL) {
1759  /* Ensure we touch the opposite edge if we can't walk over it. */
1760  l_step = l_step_opposite;
1761  }
1762  }
1763  else {
1764  l_step = NULL;
1765  }
1766 
1767  /* Break iteration when `l_step`:
1768  * - Is the first loop where we started from.
1769  * - Tagged using #BM_ELEM_TAG (meaning this loop has been visited in this iteration).
1770  * - Has its corresponding UV edge selected/unselected based on #select. */
1771  if (l_step && BM_elem_flag_test(l_step->e, BM_ELEM_TAG)) {
1772  /* Previously this check was not done and this resulted in the final edge in the edge ring
1773  * cycle to be skipped during selection (caused by old sticky selection behavior). */
1774  if (select && uvedit_edge_select_test(scene, l_step, cd_loop_uv_offset)) {
1775  break;
1776  }
1777  if (!select && !uvedit_edge_select_test(scene, l_step, cd_loop_uv_offset)) {
1778  break;
1779  }
1780  }
1781  }
1782  }
1783 
1784  return (select) ? 1 : -1;
1785 }
1786 
1789 /* -------------------------------------------------------------------- */
1794  Object **objects,
1795  const uint objects_len,
1796  UvNearestHit *hit,
1797  const bool extend,
1798  bool deselect,
1799  const bool toggle,
1800  const bool select_faces)
1801 {
1802  const bool uv_sync_select = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
1803 
1804  /* loop over objects, or just use hit->ob */
1805  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1806  if (hit && ob_index != 0) {
1807  break;
1808  }
1809  Object *obedit = hit ? hit->ob : objects[ob_index];
1810 
1811  BMFace *efa;
1812  BMLoop *l;
1813  BMIter iter, liter;
1814  UvVertMap *vmap;
1815  UvMapVert *vlist, *iterv, *startv;
1816  int i, stacksize = 0, *stack;
1817  uint a;
1818  char *flag;
1819 
1820  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1821  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1822 
1823  BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
1824 
1825  /* NOTE: we had 'use winding' so we don't consider overlapping islands as connected, see T44320
1826  * this made *every* projection split the island into front/back islands.
1827  * Keep 'use_winding' to false, see: T50970.
1828  *
1829  * Better solve this by having a delimit option for select-linked operator,
1830  * keeping island-select working as is. */
1831  vmap = BM_uv_vert_map_create(em->bm, !uv_sync_select, false);
1832 
1833  if (vmap == NULL) {
1834  continue;
1835  }
1836 
1837  stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
1838  flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
1839 
1840  if (hit == NULL) {
1841  /* Use existing selection */
1842  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1843  if (uvedit_face_visible_test(scene, efa)) {
1844  if (select_faces) {
1845  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1846  stack[stacksize] = a;
1847  stacksize++;
1848  flag[a] = 1;
1849  }
1850  }
1851  else {
1852  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1853  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1854  bool add_to_stack = true;
1855  if (uv_sync_select) {
1856  /* Special case, vertex/edge & sync select being enabled.
1857  *
1858  * Without this, a second linked select will 'grow' each time as each new
1859  * selection reaches the boundaries of islands that share vertices but not UV's.
1860  *
1861  * Rules applied here:
1862  * - This loops face isn't selected.
1863  * - The only other fully selected face is connected or,
1864  * - There are no connected fully selected faces UV-connected to this loop.
1865  */
1866  BLI_assert(!select_faces);
1867  if (uvedit_face_select_test(scene, l->f, cd_loop_uv_offset)) {
1868  /* pass */
1869  }
1870  else {
1871  BMIter liter_other;
1872  BMLoop *l_other;
1873  BM_ITER_ELEM (l_other, &liter_other, l->v, BM_LOOPS_OF_VERT) {
1874  if ((l != l_other) &&
1875  !BM_loop_uv_share_vert_check(l, l_other, cd_loop_uv_offset) &&
1876  uvedit_face_select_test(scene, l_other->f, cd_loop_uv_offset)) {
1877  add_to_stack = false;
1878  break;
1879  }
1880  }
1881  }
1882  }
1883 
1884  if (add_to_stack) {
1885  stack[stacksize] = a;
1886  stacksize++;
1887  flag[a] = 1;
1888  break;
1889  }
1890  }
1891  }
1892  }
1893  }
1894  }
1895  }
1896  else {
1897  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1898  if (efa == hit->efa) {
1899  stack[stacksize] = a;
1900  stacksize++;
1901  flag[a] = 1;
1902  break;
1903  }
1904  }
1905  }
1906 
1907  while (stacksize > 0) {
1908 
1909  stacksize--;
1910  a = stack[stacksize];
1911 
1912  efa = BM_face_at_index(em->bm, a);
1913 
1914  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1915 
1916  /* make_uv_vert_map_EM sets verts tmp.l to the indices */
1917  vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
1918 
1919  startv = vlist;
1920 
1921  for (iterv = vlist; iterv; iterv = iterv->next) {
1922  if (iterv->separate) {
1923  startv = iterv;
1924  }
1925  if (iterv->poly_index == a) {
1926  break;
1927  }
1928  }
1929 
1930  for (iterv = startv; iterv; iterv = iterv->next) {
1931  if ((startv != iterv) && (iterv->separate)) {
1932  break;
1933  }
1934  if (!flag[iterv->poly_index]) {
1935  flag[iterv->poly_index] = 1;
1936  stack[stacksize] = iterv->poly_index;
1937  stacksize++;
1938  }
1939  }
1940  }
1941  }
1942 
1943  /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
1944  if ((toggle == true) && (extend == false) && (deselect == false)) {
1945  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1946  bool found_selected = false;
1947  if (!flag[a]) {
1948  continue;
1949  }
1950 
1951  if (select_faces) {
1953  found_selected = true;
1954  }
1955  }
1956  else {
1957  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1958  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1959  found_selected = true;
1960  break;
1961  }
1962  }
1963 
1964  if (found_selected) {
1965  deselect = true;
1966  break;
1967  }
1968  }
1969  }
1970  }
1971 
1972 #define SET_SELECTION(value) \
1973  if (select_faces) { \
1974  BM_face_select_set(em->bm, efa, value); \
1975  } \
1976  else { \
1977  uvedit_face_select_set(scene, em, efa, value, false, cd_loop_uv_offset); \
1978  } \
1979  (void)0
1980 
1981  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1982  if (!flag[a]) {
1983  if (!extend && !deselect && !toggle) {
1984  SET_SELECTION(false);
1985  }
1986  continue;
1987  }
1988 
1989  if (!deselect) {
1990  SET_SELECTION(true);
1991  }
1992  else {
1993  SET_SELECTION(false);
1994  }
1995  }
1996 
1997 #undef SET_SELECTION
1998 
1999  MEM_freeN(stack);
2000  MEM_freeN(flag);
2001  BM_uv_vert_map_free(vmap);
2002 
2003  if (uv_sync_select) {
2004  if (deselect) {
2005  EDBM_deselect_flush(em);
2006  }
2007  else {
2008  if (!select_faces) {
2010  }
2011  }
2012  }
2013  }
2014 }
2015 
2017  BMVert *eve,
2018  const int cd_loop_uv_offset)
2019 {
2020  BMIter liter;
2021  BMLoop *l;
2022 
2023  BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
2024  if (!uvedit_face_visible_test(scene, l->f)) {
2025  continue;
2026  }
2027 
2028  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
2029  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2030  return luv->uv;
2031  }
2032  }
2033 
2034  return NULL;
2035 }
2036 
2039 /* -------------------------------------------------------------------- */
2043 static int uv_select_more_less(bContext *C, const bool select)
2044 {
2046  ViewLayer *view_layer = CTX_data_view_layer(C);
2047 
2048  BMFace *efa;
2049  BMLoop *l;
2050  BMIter iter, liter;
2051  const ToolSettings *ts = scene->toolsettings;
2052 
2053  uint objects_len = 0;
2055  view_layer, ((View3D *)NULL), &objects_len);
2056 
2057  const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE);
2058 
2059  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2060  Object *obedit = objects[ob_index];
2061  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2062 
2063  bool changed = false;
2064 
2065  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2066 
2067  if (ts->uv_flag & UV_SYNC_SELECTION) {
2068  if (select) {
2069  EDBM_select_more(em, true);
2070  }
2071  else {
2072  EDBM_select_less(em, true);
2073  }
2074 
2077  continue;
2078  }
2079 
2080  if (is_uv_face_selectmode) {
2081 
2082  /* clear tags */
2084 
2085  /* mark loops to be selected */
2086  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2087  if (uvedit_face_visible_test(scene, efa)) {
2088 
2089  if (select) {
2090 #define NEIGHBORING_FACE_IS_SEL 1
2091 #define CURR_FACE_IS_UNSEL 2
2092 
2093  int sel_state = 0;
2094 
2095  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2096  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2097  if (luv->flag & MLOOPUV_VERTSEL) {
2098  sel_state |= NEIGHBORING_FACE_IS_SEL;
2099  }
2100  else {
2101  sel_state |= CURR_FACE_IS_UNSEL;
2102  }
2103 
2104  if (!(luv->flag & MLOOPUV_EDGESEL)) {
2105  sel_state |= CURR_FACE_IS_UNSEL;
2106  }
2107 
2108  /* If the current face is not selected and at least one neighboring face is
2109  * selected, then tag the current face to grow selection. */
2110  if (sel_state == (NEIGHBORING_FACE_IS_SEL | CURR_FACE_IS_UNSEL)) {
2112  changed = true;
2113  break;
2114  }
2115  }
2116 
2117 #undef NEIGHBORING_FACE_IS_SEL
2118 #undef CURR_FACE_IS_UNSEL
2119  }
2120  else {
2121  if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
2122  continue;
2123  }
2124  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2125  /* Deselect face when at least one of the surrounding faces is not selected */
2126  if (!uvedit_vert_is_all_other_faces_selected(scene, l, cd_loop_uv_offset)) {
2128  changed = true;
2129  break;
2130  }
2131  }
2132  }
2133  }
2134  }
2135  }
2136  else {
2137 
2138  /* clear tags */
2139  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2140  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2142  }
2143  }
2144 
2145  /* mark loops to be selected */
2146  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2147  if (uvedit_face_visible_test(scene, efa)) {
2148  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2149 
2150  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2151 
2152  if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
2155  changed = true;
2156  }
2157  }
2158  }
2159  }
2160  }
2161 
2162  if (changed) {
2163  if (is_uv_face_selectmode) {
2164  /* Select tagged faces. */
2166  }
2167  else {
2168  /* Select tagged loops. */
2170  /* Set/unset edge flags based on selected verts. */
2171  if (select) {
2173  }
2174  else {
2176  }
2177  }
2180  }
2181  }
2182  MEM_freeN(objects);
2183 
2184  return OPERATOR_FINISHED;
2185 }
2186 
2188 {
2189  return uv_select_more_less(C, true);
2190 }
2191 
2193 {
2194  /* identifiers */
2195  ot->name = "Select More";
2196  ot->description = "Select more UV vertices connected to initial selection";
2197  ot->idname = "UV_OT_select_more";
2199 
2200  /* api callbacks */
2203 }
2204 
2206 {
2207  return uv_select_more_less(C, false);
2208 }
2209 
2211 {
2212  /* identifiers */
2213  ot->name = "Select Less";
2214  ot->description = "Deselect UV vertices at the boundary of each selection region";
2215  ot->idname = "UV_OT_select_less";
2217 
2218  /* api callbacks */
2221 }
2222 
2225 /* -------------------------------------------------------------------- */
2230 {
2231  const ToolSettings *ts = scene->toolsettings;
2232  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2233  BMFace *efa;
2234  BMLoop *l;
2235  BMIter iter, liter;
2236  MLoopUV *luv;
2237 
2238  if (ts->uv_flag & UV_SYNC_SELECTION) {
2239  return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
2240  }
2241 
2242  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2243  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2244  if (!uvedit_face_visible_test(scene, efa)) {
2245  continue;
2246  }
2247  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2248  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2249  if (luv->flag & MLOOPUV_VERTSEL) {
2250  return true;
2251  }
2252  }
2253  }
2254  return false;
2255 }
2256 
2258  Object **objects,
2259  const uint objects_len)
2260 {
2261  bool found = false;
2262  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2263  Object *obedit = objects[ob_index];
2264  if (uvedit_select_is_any_selected(scene, obedit)) {
2265  found = true;
2266  break;
2267  }
2268  }
2269  return found;
2270 }
2271 
2272 static void uv_select_all(const Scene *scene, BMEditMesh *em, bool select_all)
2273 {
2274  BMFace *efa;
2275  BMLoop *l;
2276  BMIter iter, liter;
2277  MLoopUV *luv;
2278  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2279  const int uv_select_flags = (MLOOPUV_VERTSEL | MLOOPUV_EDGESEL);
2280  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2281  if (!uvedit_face_visible_test(scene, efa)) {
2282  continue;
2283  }
2284  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2285  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2286  SET_FLAG_FROM_TEST(luv->flag, select_all, uv_select_flags);
2287  }
2288  }
2289 }
2290 
2291 static void uv_select_invert(const Scene *scene, BMEditMesh *em)
2292 {
2293  const ToolSettings *ts = scene->toolsettings;
2294  BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0);
2295 
2296  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2297  BMFace *efa;
2298  BMLoop *l;
2299  BMIter iter, liter;
2300  MLoopUV *luv;
2301  char uv_selectmode = ts->uv_selectmode;
2302  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2303  if (!uvedit_face_visible_test(scene, efa)) {
2304  continue;
2305  }
2306  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2307  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2308  if (ELEM(uv_selectmode, UV_SELECT_EDGE, UV_SELECT_FACE)) {
2309  /* Use #MLOOPUV_EDGESEL to flag edges that must be selected. */
2310  luv->flag ^= MLOOPUV_EDGESEL;
2311  luv->flag &= ~MLOOPUV_VERTSEL;
2312  }
2313  /* Use #MLOOPUV_VERTSEL to flag verts that must be selected. */
2314  else if (ELEM(uv_selectmode, UV_SELECT_VERTEX, UV_SELECT_ISLAND)) {
2315  luv->flag ^= MLOOPUV_VERTSEL;
2316  luv->flag &= ~MLOOPUV_EDGESEL;
2317  }
2318  }
2319  }
2320 
2321  /* Flush based on uv vert/edge flags and current UV select mode */
2322  if (ELEM(uv_selectmode, UV_SELECT_EDGE, UV_SELECT_FACE)) {
2324  }
2325  else if (ELEM(uv_selectmode, UV_SELECT_VERTEX, UV_SELECT_ISLAND)) {
2327  }
2328 }
2329 
2330 static void uv_select_all_perform(const Scene *scene, Object *obedit, int action)
2331 {
2332  const ToolSettings *ts = scene->toolsettings;
2333  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2334 
2335  if (action == SEL_TOGGLE) {
2337  }
2338 
2339  if (ts->uv_flag & UV_SYNC_SELECTION) {
2340  switch (action) {
2341  case SEL_TOGGLE:
2343  break;
2344  case SEL_SELECT:
2346  break;
2347  case SEL_DESELECT:
2349  break;
2350  case SEL_INVERT:
2351  EDBM_select_swap(em);
2353  break;
2354  }
2355  }
2356  else {
2357  switch (action) {
2358  case SEL_SELECT:
2359  uv_select_all(scene, em, true);
2360  break;
2361  case SEL_DESELECT:
2362  uv_select_all(scene, em, false);
2363  break;
2364  case SEL_INVERT:
2365  uv_select_invert(scene, em);
2366  break;
2367  }
2368  }
2369 }
2370 
2372  Object **objects,
2373  const uint objects_len,
2374  int action,
2375  const Object *ob_exclude)
2376 {
2377  if (action == SEL_TOGGLE) {
2378  action = uvedit_select_is_any_selected_multi(scene, objects, objects_len) ? SEL_DESELECT :
2379  SEL_SELECT;
2380  }
2381 
2382  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2383  Object *obedit = objects[ob_index];
2384  if (ob_exclude && (obedit == ob_exclude)) {
2385  continue;
2386  }
2387  uv_select_all_perform(scene, obedit, action);
2388  }
2389 }
2390 
2392  Object **objects,
2393  const uint objects_len,
2394  int action)
2395 {
2396  uv_select_all_perform_multi_ex(scene, objects, objects_len, action, NULL);
2397 }
2398 
2400 {
2403  const ToolSettings *ts = scene->toolsettings;
2404  ViewLayer *view_layer = CTX_data_view_layer(C);
2405 
2406  int action = RNA_enum_get(op->ptr, "action");
2407 
2408  uint objects_len = 0;
2410  view_layer, ((View3D *)NULL), &objects_len);
2411 
2412  uv_select_all_perform_multi(scene, objects, objects_len, action);
2413 
2414  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2415  Object *obedit = objects[ob_index];
2417  }
2418 
2419  MEM_freeN(objects);
2420 
2421  return OPERATOR_FINISHED;
2422 }
2423 
2425 {
2426  /* identifiers */
2427  ot->name = "(De)select All";
2428  ot->description = "Change selection of all UV vertices";
2429  ot->idname = "UV_OT_select_all";
2431 
2432  /* api callbacks */
2435 
2437 }
2438 
2441 /* -------------------------------------------------------------------- */
2446  Object **objects,
2447  uint objects_len,
2448  const float co[2],
2449  const struct SelectPick_Params *params)
2450 {
2452  const ARegion *region = CTX_wm_region(C);
2454  const ToolSettings *ts = scene->toolsettings;
2455  UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(&region->v2d, 75.0f);
2456  int selectmode, sticky;
2457  bool found_item = false;
2458  /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
2459  int flush = 0;
2460 
2461  /* Penalty (in pixels) applied to elements that are already selected
2462  * so elements that aren't already selected are prioritized. */
2463  const float penalty_dist = 3.0f * U.pixelsize;
2464 
2465  /* retrieve operation mode */
2466  if (ts->uv_flag & UV_SYNC_SELECTION) {
2467  if (ts->selectmode & SCE_SELECT_FACE) {
2468  selectmode = UV_SELECT_FACE;
2469  }
2470  else if (ts->selectmode & SCE_SELECT_EDGE) {
2471  selectmode = UV_SELECT_EDGE;
2472  }
2473  else {
2474  selectmode = UV_SELECT_VERTEX;
2475  }
2476 
2477  sticky = SI_STICKY_DISABLE;
2478  }
2479  else {
2480  selectmode = ts->uv_selectmode;
2481  sticky = ts->uv_sticky;
2482  }
2483 
2484  /* find nearest element */
2485  if (selectmode == UV_SELECT_VERTEX) {
2486  /* find vertex */
2487  found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit);
2488  if (found_item) {
2489  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
2492  }
2493  }
2494  }
2495  else if (selectmode == UV_SELECT_EDGE) {
2496  /* find edge */
2497  found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, penalty_dist, &hit);
2498  if (found_item) {
2499  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
2502  }
2503  }
2504  }
2505  else if (selectmode == UV_SELECT_FACE) {
2506  /* find face */
2507  found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit);
2508 
2509  if (!found_item) {
2510  /* Fallback, perform a second pass without a limited threshold,
2511  * which succeeds as long as the cursor is inside the UV face.
2512  * Useful when zoomed in, to select faces with distant screen-space face centers. */
2513  hit.dist_sq = FLT_MAX;
2514  found_item = uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, &hit, true);
2515  }
2516 
2517  if (found_item) {
2520  }
2521  }
2522  else if (selectmode == UV_SELECT_ISLAND) {
2523  found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, 0.0f, &hit);
2524 
2525  if (!found_item) {
2526  /* Without this, we can be within the face of an island but too far from an edge,
2527  * see face selection comment for details. */
2528  hit.dist_sq = FLT_MAX;
2529  found_item = uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, &hit, true);
2530  }
2531  }
2532 
2533  bool found = found_item;
2534  bool changed = false;
2535 
2536  bool is_selected = false;
2537  if (found) {
2538  Object *obedit = hit.ob;
2539  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2540  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2541  if (selectmode == UV_SELECT_FACE) {
2542  is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset);
2543  }
2544  else if (selectmode == UV_SELECT_EDGE) {
2545  is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset);
2546  }
2547  else {
2548  /* Vertex or island. For island (if we were using #uv_find_nearest_face_multi_ex, see above),
2549  * `hit.l` is NULL, use `hit.efa` instead. */
2550  if (hit.l != NULL) {
2551  is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
2552  }
2553  else {
2554  is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset);
2555  }
2556  }
2557  }
2558 
2559  if (params->sel_op == SEL_OP_SET) {
2560  if ((found && params->select_passthrough) && is_selected) {
2561  found = false;
2562  }
2563  else if (found || params->deselect_all) {
2564  /* Deselect everything. */
2565  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
2566  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2567  Object *obedit = objects[ob_index];
2569  }
2570  changed = true;
2571  }
2572  }
2573 
2574  if (found) {
2575  Object *obedit = hit.ob;
2576  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2577  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2578 
2579  if (selectmode == UV_SELECT_ISLAND) {
2580  const bool extend = params->sel_op == SEL_OP_ADD;
2581  const bool deselect = params->sel_op == SEL_OP_SUB;
2582  const bool toggle = params->sel_op == SEL_OP_XOR;
2583  /* Current behavior of 'extend'
2584  * is actually toggling, so pass extend flag as 'toggle' here */
2585  uv_select_linked_multi(scene, objects, objects_len, &hit, extend, deselect, toggle, false);
2586  /* TODO: check if this actually changed. */
2587  changed = true;
2588  }
2589  else {
2591  bool select_value = false;
2592  switch (params->sel_op) {
2593  case SEL_OP_ADD: {
2594  select_value = true;
2595  break;
2596  }
2597  case SEL_OP_SUB: {
2598  select_value = false;
2599  break;
2600  }
2601  case SEL_OP_XOR: {
2602  select_value = !is_selected;
2603  break;
2604  }
2605  case SEL_OP_SET: {
2606  /* Deselect has already been performed. */
2607  select_value = true;
2608  break;
2609  }
2610  case SEL_OP_AND: {
2611  BLI_assert_unreachable(); /* Doesn't make sense for picking. */
2612  break;
2613  }
2614  }
2615 
2616  if (selectmode == UV_SELECT_FACE) {
2618  scene, em, hit.efa, select_value, true, cd_loop_uv_offset);
2619  flush = 1;
2620  }
2621  else if (selectmode == UV_SELECT_EDGE) {
2623  scene, em, hit.l, select_value, true, cd_loop_uv_offset);
2624  flush = 1;
2625  }
2626  else if (selectmode == UV_SELECT_VERTEX) {
2627  uvedit_uv_select_set_with_sticky(scene, em, hit.l, select_value, true, cd_loop_uv_offset);
2628  flush = 1;
2629  }
2630  else {
2632  }
2633 
2634  /* De-selecting an edge may deselect a face too - validate. */
2635  if (ts->uv_flag & UV_SYNC_SELECTION) {
2636  if (select_value == false) {
2638  }
2639  }
2640 
2641  /* (de)select sticky UV nodes. */
2642  if (sticky != SI_STICKY_DISABLE) {
2643  flush = select_value ? 1 : -1;
2644  }
2645 
2646  changed = true;
2647  }
2648 
2649  if (ts->uv_flag & UV_SYNC_SELECTION) {
2650  if (flush != 0) {
2652  }
2653  }
2654  else {
2655  /* Setting the selection implies a single element, which doesn't need to be flushed. */
2656  if (params->sel_op != SEL_OP_SET) {
2658  }
2659  }
2660  }
2661 
2662  if (changed && found) {
2663  /* Only update the `hit` object as de-selecting all will have refreshed the others. */
2664  Object *obedit = hit.ob;
2666  }
2667 
2668  return changed || found;
2669 }
2670 static bool uv_mouse_select(bContext *C, const float co[2], const struct SelectPick_Params *params)
2671 {
2672  ViewLayer *view_layer = CTX_data_view_layer(C);
2673  uint objects_len = 0;
2675  view_layer, ((View3D *)NULL), &objects_len);
2676  bool changed = uv_mouse_select_multi(C, objects, objects_len, co, params);
2677  MEM_freeN(objects);
2678  return changed;
2679 }
2680 
2682 {
2683  float co[2];
2684 
2685  RNA_float_get_array(op->ptr, "location", co);
2686 
2687  struct SelectPick_Params params = {0};
2689 
2690  const bool changed = uv_mouse_select(C, co, &params);
2691 
2692  if (changed) {
2694  }
2696 }
2697 
2698 static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2699 {
2700  const ARegion *region = CTX_wm_region(C);
2701  float co[2];
2702 
2703  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2704  RNA_float_set_array(op->ptr, "location", co);
2705 
2706  const int retval = uv_select_exec(C, op);
2707 
2708  return WM_operator_flag_only_pass_through_on_press(retval, event);
2709 }
2710 
2712 {
2713  /* identifiers */
2714  ot->name = "Select";
2715  ot->description = "Select UV vertices";
2716  ot->idname = "UV_OT_select";
2717  ot->flag = OPTYPE_UNDO;
2718 
2719  /* api callbacks */
2720  ot->exec = uv_select_exec;
2722  ot->poll = ED_operator_uvedit; /* requires space image */
2724 
2725  /* properties */
2726  PropertyRNA *prop;
2727 
2729 
2730  prop = RNA_def_float_vector(
2731  ot->srna,
2732  "location",
2733  2,
2734  NULL,
2735  -FLT_MAX,
2736  FLT_MAX,
2737  "Location",
2738  "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
2739  -100.0f,
2740  100.0f);
2742 }
2743 
2746 /* -------------------------------------------------------------------- */
2753 };
2754 
2756  Object **objects,
2757  uint objects_len,
2758  const float co[2],
2759  const bool extend,
2760  enum eUVLoopGenericType loop_type)
2761 {
2762  const ARegion *region = CTX_wm_region(C);
2765  const ToolSettings *ts = scene->toolsettings;
2766  UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
2767  bool found_item = false;
2768  /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
2769  int flush = 0;
2770 
2771  /* Find edge. */
2772  found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, 0.0f, &hit);
2773  if (!found_item) {
2774  return OPERATOR_CANCELLED;
2775  }
2776 
2777  Object *obedit = hit.ob;
2778  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2779 
2780  /* Do selection. */
2781  if (!extend) {
2782  uv_select_all_perform_multi_ex(scene, objects, objects_len, SEL_DESELECT, obedit);
2783  }
2784 
2785  if (loop_type == UV_LOOP_SELECT) {
2787  flush = uv_select_faceloop(scene, obedit, &hit, extend);
2788  }
2789  else {
2790  flush = uv_select_edgeloop(scene, obedit, &hit, extend);
2791  }
2792  }
2793  else if (loop_type == UV_RING_SELECT) {
2794  flush = uv_select_edgering(scene, obedit, &hit, extend);
2795  }
2796  else {
2798  }
2799 
2800  if (ts->uv_flag & UV_SYNC_SELECTION) {
2801  if (flush == 1) {
2802  EDBM_select_flush(em);
2803  }
2804  else if (flush == -1) {
2805  EDBM_deselect_flush(em);
2806  }
2807  }
2808  else {
2810  }
2811 
2812  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2813  Object *obiter = objects[ob_index];
2815  }
2816 
2818 }
2820  const float co[2],
2821  const bool extend,
2822  enum eUVLoopGenericType loop_type)
2823 {
2824  ViewLayer *view_layer = CTX_data_view_layer(C);
2825  uint objects_len = 0;
2827  view_layer, ((View3D *)NULL), &objects_len);
2828  int ret = uv_mouse_select_loop_generic_multi(C, objects, objects_len, co, extend, loop_type);
2829  MEM_freeN(objects);
2830  return ret;
2831 }
2832 
2835 /* -------------------------------------------------------------------- */
2840 {
2841  float co[2];
2842 
2843  RNA_float_get_array(op->ptr, "location", co);
2844  const bool extend = RNA_boolean_get(op->ptr, "extend");
2845 
2846  return uv_mouse_select_loop_generic(C, co, extend, UV_LOOP_SELECT);
2847 }
2848 
2849 static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2850 {
2851  const ARegion *region = CTX_wm_region(C);
2852  float co[2];
2853 
2854  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2855  RNA_float_set_array(op->ptr, "location", co);
2856 
2857  const int retval = uv_select_loop_exec(C, op);
2858 
2859  return WM_operator_flag_only_pass_through_on_press(retval, event);
2860 }
2861 
2863 {
2864  /* identifiers */
2865  ot->name = "Loop Select";
2866  ot->description = "Select a loop of connected UV vertices";
2867  ot->idname = "UV_OT_select_loop";
2868  ot->flag = OPTYPE_UNDO;
2869 
2870  /* api callbacks */
2873  ot->poll = ED_operator_uvedit; /* requires space image */
2874 
2875  /* properties */
2876  PropertyRNA *prop;
2877  prop = RNA_def_boolean(ot->srna,
2878  "extend",
2879  0,
2880  "Extend",
2881  "Extend selection rather than clearing the existing selection");
2883  prop = RNA_def_float_vector(
2884  ot->srna,
2885  "location",
2886  2,
2887  NULL,
2888  -FLT_MAX,
2889  FLT_MAX,
2890  "Location",
2891  "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
2892  -100.0f,
2893  100.0f);
2895 }
2896 
2899 /* -------------------------------------------------------------------- */
2904 {
2905  float co[2];
2906  RNA_float_get_array(op->ptr, "location", co);
2907  const bool extend = RNA_boolean_get(op->ptr, "extend");
2908  return uv_mouse_select_loop_generic(C, co, extend, UV_RING_SELECT);
2909 }
2910 
2911 static int uv_select_edge_ring_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2912 {
2913  const ARegion *region = CTX_wm_region(C);
2914  float co[2];
2915 
2916  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2917  RNA_float_set_array(op->ptr, "location", co);
2918 
2919  const int retval = uv_select_edge_ring_exec(C, op);
2920 
2921  return WM_operator_flag_only_pass_through_on_press(retval, event);
2922 }
2923 
2925 {
2926  /* identifiers */
2927  ot->name = "Edge Ring Select";
2928  ot->description = "Select an edge ring of connected UV vertices";
2929  ot->idname = "UV_OT_select_edge_ring";
2930  ot->flag = OPTYPE_UNDO;
2931 
2932  /* api callbacks */
2935  ot->poll = ED_operator_uvedit; /* requires space image */
2936 
2937  /* properties */
2938  PropertyRNA *prop;
2939  prop = RNA_def_boolean(ot->srna,
2940  "extend",
2941  0,
2942  "Extend",
2943  "Extend selection rather than clearing the existing selection");
2945  prop = RNA_def_float_vector(
2946  ot->srna,
2947  "location",
2948  2,
2949  NULL,
2950  -FLT_MAX,
2951  FLT_MAX,
2952  "Location",
2953  "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
2954  -100.0f,
2955  100.0f);
2957 }
2958 
2961 /* -------------------------------------------------------------------- */
2965 static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
2966 {
2967  const ARegion *region = CTX_wm_region(C);
2969  const ToolSettings *ts = scene->toolsettings;
2970  ViewLayer *view_layer = CTX_data_view_layer(C);
2971  bool extend = true;
2972  bool deselect = false;
2973  bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
2974 
2975  UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
2976 
2977  if (pick) {
2978  extend = RNA_boolean_get(op->ptr, "extend");
2979  deselect = RNA_boolean_get(op->ptr, "deselect");
2980  }
2981 
2982  uint objects_len = 0;
2984  view_layer, ((View3D *)NULL), &objects_len);
2985 
2986  if (pick) {
2987  float co[2];
2988 
2989  if (event) {
2990  /* invoke */
2991  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2992  RNA_float_set_array(op->ptr, "location", co);
2993  }
2994  else {
2995  /* exec */
2996  RNA_float_get_array(op->ptr, "location", co);
2997  }
2998 
2999  if (!uv_find_nearest_edge_multi(scene, objects, objects_len, co, 0.0f, &hit)) {
3000  MEM_freeN(objects);
3001  return OPERATOR_CANCELLED;
3002  }
3003  }
3004 
3005  if (!extend && !deselect) {
3006  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
3007  }
3008 
3010  scene, objects, objects_len, pick ? &hit : NULL, extend, deselect, false, select_faces);
3011 
3012  /* weak!, but works */
3013  Object **objects_free = objects;
3014  if (pick) {
3015  objects = &hit.ob;
3016  objects_len = 1;
3017  }
3018 
3019  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3020  Object *obedit = objects[ob_index];
3023  }
3024 
3025  MEM_SAFE_FREE(objects_free);
3026 
3027  return OPERATOR_FINISHED;
3028 }
3029 
3031 {
3032  return uv_select_linked_internal(C, op, NULL, false);
3033 }
3034 
3036 {
3037  /* identifiers */
3038  ot->name = "Select Linked";
3039  ot->description = "Select all UV vertices linked to the active UV map";
3040  ot->idname = "UV_OT_select_linked";
3041 
3042  /* api callbacks */
3044  ot->poll = ED_operator_uvedit; /* requires space image */
3045 
3046  /* flags */
3048 }
3049 
3052 /* -------------------------------------------------------------------- */
3057 {
3058  return uv_select_linked_internal(C, op, event, true);
3059 }
3060 
3062 {
3063  return uv_select_linked_internal(C, op, NULL, true);
3064 }
3065 
3067 {
3068  /* identifiers */
3069  ot->name = "Select Linked Pick";
3070  ot->description = "Select all UV vertices linked under the mouse";
3071  ot->idname = "UV_OT_select_linked_pick";
3072 
3073  /* flags */
3075 
3076  /* api callbacks */
3079  ot->poll = ED_operator_uvedit; /* requires space image */
3080 
3081  /* properties */
3082  PropertyRNA *prop;
3083  prop = RNA_def_boolean(ot->srna,
3084  "extend",
3085  0,
3086  "Extend",
3087  "Extend selection rather than clearing the existing selection");
3089  prop = RNA_def_boolean(ot->srna,
3090  "deselect",
3091  0,
3092  "Deselect",
3093  "Deselect linked UV vertices rather than selecting them");
3095  prop = RNA_def_float_vector(
3096  ot->srna,
3097  "location",
3098  2,
3099  NULL,
3100  -FLT_MAX,
3101  FLT_MAX,
3102  "Location",
3103  "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
3104  -100.0f,
3105  100.0f);
3107 }
3108 
3111 /* -------------------------------------------------------------------- */
3122 {
3125  ViewLayer *view_layer = CTX_data_view_layer(C);
3126  const ToolSettings *ts = scene->toolsettings;
3127 
3128  BMFace *efa;
3129  BMLoop *l;
3130  BMIter iter, liter;
3131  MLoopUV *luv;
3132 
3133  if (ts->uv_flag & UV_SYNC_SELECTION) {
3134  BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
3135  return OPERATOR_CANCELLED;
3136  }
3137 
3138  bool changed_multi = false;
3139 
3140  uint objects_len = 0;
3142  view_layer, ((View3D *)NULL), &objects_len);
3143 
3144  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3145  Object *obedit = objects[ob_index];
3146  BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
3147 
3148  bool changed = false;
3149 
3150  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
3151 
3152  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
3153  bool is_sel = false;
3154  bool is_unsel = false;
3155 
3156  if (!uvedit_face_visible_test(scene, efa)) {
3157  continue;
3158  }
3159 
3160  /* are we all selected? */
3161  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3162  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3163 
3164  if ((luv->flag & MLOOPUV_VERTSEL) || (luv->flag & MLOOPUV_EDGESEL)) {
3165  is_sel = true;
3166  }
3167  if (!(luv->flag & MLOOPUV_VERTSEL) || !(luv->flag & MLOOPUV_EDGESEL)) {
3168  is_unsel = true;
3169  }
3170 
3171  /* we have mixed selection, bail out */
3172  if (is_sel && is_unsel) {
3173  break;
3174  }
3175  }
3176 
3177  if (is_sel && is_unsel) {
3178  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3179  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3180  luv->flag &= ~(MLOOPUV_VERTSEL | MLOOPUV_EDGESEL);
3181  }
3182 
3183  changed = true;
3184  }
3185  }
3186 
3187  if (changed) {
3188  changed_multi = true;
3191  }
3192  }
3193  MEM_freeN(objects);
3194 
3195  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3196 }
3197 
3199 {
3200  /* identifiers */
3201  ot->name = "Select Split";
3202  ot->description = "Select only entirely selected faces";
3203  ot->idname = "UV_OT_select_split";
3205 
3206  /* api callbacks */
3208  ot->poll = ED_operator_uvedit; /* requires space image */
3209 }
3210 
3212  const ToolSettings *ts,
3213  Object *obedit)
3214 {
3215  if (ts->uv_flag & UV_SYNC_SELECTION) {
3218  }
3219  else {
3220  Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
3222  /* Only for region redraw. */
3224  }
3225 }
3226 
3229 /* -------------------------------------------------------------------- */
3239  BMEditMesh *em,
3240  UvVertMap *vmap,
3241  const uint efa_index,
3242  BMLoop *l,
3243  const bool select,
3244  const int cd_loop_uv_offset)
3245 {
3246  UvMapVert *start_vlist = NULL, *vlist_iter;
3247  BMFace *efa_vlist;
3248 
3249  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
3250 
3251  vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
3252 
3253  while (vlist_iter) {
3254  if (vlist_iter->separate) {
3255  start_vlist = vlist_iter;
3256  }
3257 
3258  if (efa_index == vlist_iter->poly_index) {
3259  break;
3260  }
3261 
3262  vlist_iter = vlist_iter->next;
3263  }
3264 
3265  vlist_iter = start_vlist;
3266  while (vlist_iter) {
3267 
3268  if (vlist_iter != start_vlist && vlist_iter->separate) {
3269  break;
3270  }
3271 
3272  if (efa_index != vlist_iter->poly_index) {
3273  BMLoop *l_other;
3274  efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
3275  /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
3276 
3277  l_other = BM_iter_at_index(
3278  em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
3279 
3280  uvedit_uv_select_set(scene, em, l_other, select, false, cd_loop_uv_offset);
3281  }
3282  vlist_iter = vlist_iter->next;
3283  }
3284 }
3285 
3296 static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, const bool select)
3297 {
3298  /* Selecting UV Faces with some modes requires us to change
3299  * the selection in other faces (depending on the sticky mode).
3300  *
3301  * This only needs to be done when the Mesh is not used for
3302  * selection (so for sticky modes, vertex or location based). */
3303 
3304  const ToolSettings *ts = scene->toolsettings;
3305  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3306  BMFace *efa;
3307  BMLoop *l;
3308  BMIter iter, liter;
3309  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3310 
3311  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 &&
3313 
3314  struct UvVertMap *vmap;
3315  uint efa_index;
3316 
3318  vmap = BM_uv_vert_map_create(em->bm, false, false);
3319  if (vmap == NULL) {
3320  return;
3321  }
3322 
3323  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
3324  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
3325  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3326  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3327  if (select) {
3328  luv->flag |= MLOOPUV_EDGESEL;
3330  scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
3331  }
3332  else {
3333  luv->flag &= ~MLOOPUV_EDGESEL;
3334  if (!uvedit_vert_is_face_select_any_other(scene, l, cd_loop_uv_offset)) {
3336  scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
3337  }
3338  }
3339  }
3340  }
3341  }
3342  BM_uv_vert_map_free(vmap);
3343  }
3344  else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
3345  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3346  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
3347  uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
3348  }
3349  }
3350  }
3351 }
3352 
3363 static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, const bool select)
3364 {
3365  /* Selecting UV Loops with some modes requires us to change
3366  * the selection in other faces (depending on the sticky mode).
3367  *
3368  * This only needs to be done when the Mesh is not used for
3369  * selection (so for sticky modes, vertex or location based). */
3370 
3371  const ToolSettings *ts = scene->toolsettings;
3372  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3373  BMFace *efa;
3374  BMLoop *l;
3375  BMIter iter, liter;
3376 
3377  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3378 
3379  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && ts->uv_sticky == SI_STICKY_VERTEX) {
3380  /* Tag all verts as untouched, then touch the ones that have a face center
3381  * in the loop and select all MLoopUV's that use a touched vert. */
3383 
3384  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3385  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3388  }
3389  }
3390  }
3391 
3392  /* now select tagged verts */
3393  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3394  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3395  if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
3396  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
3397  }
3398  }
3399  }
3400  }
3401  else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && ts->uv_sticky == SI_STICKY_LOC) {
3402  struct UvVertMap *vmap;
3403  uint efa_index;
3404 
3406  vmap = BM_uv_vert_map_create(em->bm, false, false);
3407  if (vmap == NULL) {
3408  return;
3409  }
3410 
3411  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
3412  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3415  scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
3416  }
3417  }
3418  }
3419  BM_uv_vert_map_free(vmap);
3420  }
3421  else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
3422  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3423  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3425  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
3426  }
3427  }
3428  }
3429  }
3430 }
3431 
3443 {
3444  const ToolSettings *ts = scene->toolsettings;
3445  BMFace *efa;
3446  BMLoop *l;
3447  BMIter iter, liter;
3448 
3449  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3450 
3451  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 &&
3453  /* Use the #MLOOPUV_EDGESEL flag to identify which verts must to be selected */
3454  struct UvVertMap *vmap;
3455  uint efa_index;
3456  /* Clear UV vert flags */
3457  bm_uv_flag_clear(scene, em->bm, MLOOPUV_VERTSEL, cd_loop_uv_offset);
3458 
3460  vmap = BM_uv_vert_map_create(em->bm, false, false);
3461  if (vmap == NULL) {
3462  return;
3463  }
3464  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
3465  if (!uvedit_face_visible_test(scene, efa)) {
3466  /* This visibility check could be removed? Simply relying on edge flags to ensure
3467  * visibility might be sufficient. */
3468  continue;
3469  }
3470  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3471  MLoopUV *luv;
3472  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3473  /* Select verts based on UV edge flag. */
3474  if (luv->flag & MLOOPUV_EDGESEL) {
3476  scene, em, vmap, efa_index, l, true, cd_loop_uv_offset);
3478  scene, em, vmap, efa_index, l->next, true, cd_loop_uv_offset);
3479  }
3480  }
3481  }
3482  BM_uv_vert_map_free(vmap);
3483  }
3484  else {
3485  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3486  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3487  MLoopUV *luv, *luv_next, *luv_prev;
3488  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3489  luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
3490  luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
3491 
3492  if (luv->flag & MLOOPUV_EDGESEL) {
3493  luv->flag |= MLOOPUV_VERTSEL;
3494  luv_next->flag |= MLOOPUV_VERTSEL;
3495  }
3496  else if (!(luv_prev->flag & MLOOPUV_EDGESEL)) {
3497  luv->flag &= ~MLOOPUV_VERTSEL;
3498  }
3499  }
3500  }
3501  }
3502 }
3503 
3506 /* -------------------------------------------------------------------- */
3511 {
3514  const ToolSettings *ts = scene->toolsettings;
3515  ViewLayer *view_layer = CTX_data_view_layer(C);
3516  const ARegion *region = CTX_wm_region(C);
3517  BMFace *efa;
3518  BMLoop *l;
3519  BMIter iter, liter;
3520  MLoopUV *luv;
3521  rctf rectf;
3522  bool pinned;
3523  const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3524  (ts->selectmode == SCE_SELECT_FACE) :
3525  (ts->uv_selectmode == UV_SELECT_FACE));
3526  const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3527  (ts->selectmode == SCE_SELECT_EDGE) :
3528  (ts->uv_selectmode == UV_SELECT_EDGE));
3529  const bool use_select_linked = !(ts->uv_flag & UV_SYNC_SELECTION) &&
3531 
3532  /* get rectangle from operator */
3534  UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
3535 
3536  const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
3537  const bool select = (sel_op != SEL_OP_SUB);
3538  const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
3539 
3540  pinned = RNA_boolean_get(op->ptr, "pinned");
3541 
3542  bool changed_multi = false;
3543 
3544  uint objects_len = 0;
3546  view_layer, ((View3D *)NULL), &objects_len);
3547 
3548  if (use_pre_deselect) {
3549  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
3550  }
3551 
3552  /* don't indent to avoid diff noise! */
3553  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3554  Object *obedit = objects[ob_index];
3555  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3556 
3557  bool changed = false;
3558 
3559  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3560 
3561  /* do actual selection */
3562  if (use_face_center && !pinned) {
3563  /* handle face selection mode */
3564  float cent[2];
3565 
3566  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3567  /* assume not touched */
3569 
3570  if (uvedit_face_visible_test(scene, efa)) {
3571  BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
3572  if (BLI_rctf_isect_pt_v(&rectf, cent)) {
3574  changed = true;
3575  }
3576  }
3577  }
3578 
3579  /* (de)selects all tagged faces and deals with sticky modes */
3580  if (changed) {
3582  }
3583  }
3584  else if (use_edge && !pinned) {
3585  bool do_second_pass = true;
3586  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3587  if (!uvedit_face_visible_test(scene, efa)) {
3588  continue;
3589  }
3590 
3591  BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
3592  MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
3593 
3594  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3595  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3596  if (BLI_rctf_isect_pt_v(&rectf, luv->uv) && BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) {
3598  scene, em, l_prev, select, false, cd_loop_uv_offset);
3599  changed = true;
3600  do_second_pass = false;
3601  }
3602  l_prev = l;
3603  luv_prev = luv;
3604  }
3605  }
3606  /* Do a second pass if no complete edges could be selected.
3607  * This matches wire-frame edit-mesh selection in the 3D view. */
3608  if (do_second_pass) {
3609  /* Second pass to check if edges partially overlap with the selection area (box). */
3610  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3611  if (!uvedit_face_visible_test(scene, efa)) {
3612  continue;
3613  }
3614  BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
3615  MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
3616 
3617  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3618  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3619  if (BLI_rctf_isect_segment(&rectf, luv_prev->uv, luv->uv)) {
3621  scene, em, l_prev, select, false, cd_loop_uv_offset);
3622  changed = true;
3623  }
3624  l_prev = l;
3625  luv_prev = luv;
3626  }
3627  }
3628  }
3629  }
3630  else {
3631  /* other selection modes */
3632  changed = true;
3634 
3635  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3636  if (!uvedit_face_visible_test(scene, efa)) {
3637  continue;
3638  }
3639  bool has_selected = false;
3640  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3641  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3642  if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
3643  if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
3644  /* UV_SYNC_SELECTION - can't do pinned selection */
3645  if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
3646  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
3648  has_selected = true;
3649  }
3650  }
3651  else if (pinned) {
3652  if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
3653  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
3655  }
3656  }
3657  }
3658  }
3659  if (has_selected && use_select_linked) {
3660  UvNearestHit hit = {
3661  .ob = obedit,
3662  .efa = efa,
3663  };
3664  uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false);
3665  }
3666  }
3667 
3668  if (ts->uv_sticky == SI_STICKY_VERTEX) {
3669  uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
3670  }
3671  }
3672 
3673  if (changed || use_pre_deselect) {
3674  changed_multi = true;
3675  if (ts->uv_flag & UV_SYNC_SELECTION) {
3677  }
3678  else {
3680  }
3682  }
3683  }
3684 
3685  MEM_freeN(objects);
3686 
3687  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3688 }
3689 
3691 {
3692  /* identifiers */
3693  ot->name = "Box Select";
3694  ot->description = "Select UV vertices using box selection";
3695  ot->idname = "UV_OT_select_box";
3696 
3697  /* api callbacks */
3701  ot->poll = ED_operator_uvedit_space_image; /* requires space image */
3703 
3704  /* flags */
3705  ot->flag = OPTYPE_UNDO;
3706 
3707  /* properties */
3708  RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
3709 
3712 }
3713 
3716 /* -------------------------------------------------------------------- */
3720 static int uv_circle_select_is_point_inside(const float uv[2],
3721  const float offset[2],
3722  const float ellipse[2])
3723 {
3724  /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
3725  const float co[2] = {
3726  (uv[0] - offset[0]) * ellipse[0],
3727  (uv[1] - offset[1]) * ellipse[1],
3728  };
3729  return len_squared_v2(co) < 1.0f;
3730 }
3731 
3732 static int uv_circle_select_is_edge_inside(const float uv_a[2],
3733  const float uv_b[2],
3734  const float offset[2],
3735  const float ellipse[2])
3736 {
3737  /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
3738  const float co_a[2] = {
3739  (uv_a[0] - offset[0]) * ellipse[0],
3740  (uv_a[1] - offset[1]) * ellipse[1],
3741  };
3742  const float co_b[2] = {
3743  (uv_b[0] - offset[0]) * ellipse[0],
3744  (uv_b[1] - offset[1]) * ellipse[1],
3745  };
3746  return dist_squared_to_line_segment_v2((const float[2]){0.0f, 0.0f}, co_a, co_b) < 1.0f;
3747 }
3748 
3750 {
3752  SpaceImage *sima = CTX_wm_space_image(C);
3754  ViewLayer *view_layer = CTX_data_view_layer(C);
3755  const ToolSettings *ts = scene->toolsettings;
3756  const ARegion *region = CTX_wm_region(C);
3757  BMFace *efa;
3758  BMLoop *l;
3759  BMIter iter, liter;
3760  MLoopUV *luv;
3761  int x, y, radius, width, height;
3762  float zoomx, zoomy;
3763  float offset[2], ellipse[2];
3764 
3765  const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3766  (ts->selectmode == SCE_SELECT_FACE) :
3767  (ts->uv_selectmode == UV_SELECT_FACE));
3768  const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3769  (ts->selectmode == SCE_SELECT_EDGE) :
3770  (ts->uv_selectmode == UV_SELECT_EDGE));
3771  const bool use_select_linked = !(ts->uv_flag & UV_SYNC_SELECTION) &&
3773 
3774  /* get operator properties */
3775  x = RNA_int_get(op->ptr, "x");
3776  y = RNA_int_get(op->ptr, "y");
3777  radius = RNA_int_get(op->ptr, "radius");
3778 
3779  /* compute ellipse size and location, not a circle since we deal
3780  * with non square image. ellipse is normalized, r = 1.0. */
3782  ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
3783 
3784  ellipse[0] = width * zoomx / radius;
3785  ellipse[1] = height * zoomy / radius;
3786 
3787  UI_view2d_region_to_view(&region->v2d, x, y, &offset[0], &offset[1]);
3788 
3789  bool changed_multi = false;
3790 
3791  uint objects_len = 0;
3793  view_layer, ((View3D *)NULL), &objects_len);
3794 
3795  const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
3797  const bool select = (sel_op != SEL_OP_SUB);
3798  const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
3799 
3800  if (use_pre_deselect) {
3801  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
3802  }
3803 
3804  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3805  Object *obedit = objects[ob_index];
3806  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3807 
3808  bool changed = false;
3809 
3810  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3811 
3812  /* do selection */
3813  if (use_face_center) {
3814  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3816  /* assume not touched */
3817  if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
3818  float cent[2];
3819  BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
3820  if (uv_circle_select_is_point_inside(cent, offset, ellipse)) {
3822  changed = true;
3823  }
3824  }
3825  }
3826 
3827  /* (de)selects all tagged faces and deals with sticky modes */
3828  if (changed) {
3830  }
3831  }
3832  else if (use_edge) {
3833  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3834  if (!uvedit_face_visible_test(scene, efa)) {
3835  continue;
3836  }
3837 
3838  BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
3839  MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
3840 
3841  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3842  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3843  if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) {
3845  scene, em, l_prev, select, false, cd_loop_uv_offset);
3846  changed = true;
3847  }
3848  l_prev = l;
3849  luv_prev = luv;
3850  }
3851  }
3852  }
3853  else {
3855 
3856  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3857  if (!uvedit_face_visible_test(scene, efa)) {
3858  continue;
3859  }
3860  bool has_selected = false;
3861  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3862  if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
3863  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3864  if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) {
3865  changed = true;
3866  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
3868  has_selected = true;
3869  }
3870  }
3871  }
3872  if (has_selected && use_select_linked) {
3873  UvNearestHit hit = {
3874  .ob = obedit,
3875  .efa = efa,
3876  };
3877  uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false);
3878  }
3879  }
3880 
3881  if (ts->uv_sticky == SI_STICKY_VERTEX) {
3882  uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
3883  }
3884  }
3885 
3886  if (changed || use_pre_deselect) {
3887  changed_multi = true;
3888  if (ts->uv_flag & UV_SYNC_SELECTION) {
3890  }
3891  else {
3893  }
3895  }
3896  }
3897  MEM_freeN(objects);
3898 
3899  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3900 }
3901 
3903 {
3904  /* identifiers */
3905  ot->name = "Circle Select";
3906  ot->description = "Select UV vertices using circle selection";
3907  ot->idname = "UV_OT_select_circle";
3908 
3909  /* api callbacks */
3913  ot->poll = ED_operator_uvedit_space_image; /* requires space image */
3916 
3917  /* flags */
3918  ot->flag = OPTYPE_UNDO;
3919 
3920  /* properties */
3923 }
3924 
3927 /* -------------------------------------------------------------------- */
3932  const rcti *clip_rect,
3933  const int mcoords[][2],
3934  const int mcoords_len,
3935  const float co_test[2])
3936 {
3937  int co_screen[2];
3939  &region->v2d, co_test[0], co_test[1], &co_screen[0], &co_screen[1]) &&
3940  BLI_rcti_isect_pt_v(clip_rect, co_screen) &&
3942  mcoords, mcoords_len, co_screen[0], co_screen[1], V2D_IS_CLIPPED)) {
3943  return true;
3944  }
3945  return false;
3946 }
3947 
3949  const rcti *clip_rect,
3950  const int mcoords[][2],
3951  const int mcoords_len,
3952  const float co_test_a[2],
3953  const float co_test_b[2])
3954 {
3955  int co_screen_a[2], co_screen_b[2];
3957  &region->v2d, co_test_a, co_test_b, co_screen_a, co_screen_b) &&
3958  BLI_rcti_isect_segment(clip_rect, co_screen_a, co_screen_b) &&
3960  mcoords, mcoords_len, UNPACK2(co_screen_a), UNPACK2(co_screen_b), V2D_IS_CLIPPED)) {
3961  return true;
3962  }
3963  return false;
3964 }
3965 
3967  const int mcoords[][2],
3968  const int mcoords_len,
3969  const eSelectOp sel_op)
3970 {
3972  const ARegion *region = CTX_wm_region(C);
3974  const ToolSettings *ts = scene->toolsettings;
3975  ViewLayer *view_layer = CTX_data_view_layer(C);
3976  const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3977  (ts->selectmode == SCE_SELECT_FACE) :
3978  (ts->uv_selectmode == UV_SELECT_FACE));
3979  const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3980  (ts->selectmode == SCE_SELECT_EDGE) :
3981  (ts->uv_selectmode == UV_SELECT_EDGE));
3982  const bool use_select_linked = !(ts->uv_flag & UV_SYNC_SELECTION) &&
3984 
3985  const bool select = (sel_op != SEL_OP_SUB);
3986  const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
3987 
3988  BMIter iter, liter;
3989 
3990  BMFace *efa;
3991  BMLoop *l;
3992  bool changed_multi = false;
3993  rcti rect;
3994 
3995  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
3996 
3997  uint objects_len = 0;
3999  view_layer, ((View3D *)NULL), &objects_len);
4000 
4001  if (use_pre_deselect) {
4002  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
4003  }
4004 
4005  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4006  Object *obedit = objects[ob_index];
4007 
4008  bool changed = false;
4009 
4010  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4011 
4012  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
4013 
4014  if (use_face_center) { /* Face Center Select. */
4015  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4017  /* assume not touched */
4018  if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
4019  float cent[2];
4020  BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
4021  if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) {
4023  changed = true;
4024  }
4025  }
4026  }
4027 
4028  /* (de)selects all tagged faces and deals with sticky modes */
4029  if (changed) {
4031  }
4032  }
4033  else if (use_edge) {
4034  bool do_second_pass = true;
4035  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4036  if (!uvedit_face_visible_test(scene, efa)) {
4037  continue;
4038  }
4039 
4040  BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
4041  MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
4042 
4043  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
4044  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4046  region, &rect, mcoords, mcoords_len, luv->uv) &&
4048  region, &rect, mcoords, mcoords_len, luv_prev->uv)) {
4050  scene, em, l_prev, select, false, cd_loop_uv_offset);
4051  do_second_pass = false;
4052  changed = true;
4053  }
4054  l_prev = l;
4055  luv_prev = luv;
4056  }
4057  }
4058  /* Do a second pass if no complete edges could be selected.
4059  * This matches wire-frame edit-mesh selection in the 3D view. */
4060  if (do_second_pass) {
4061  /* Second pass to check if edges partially overlap with the selection area (lasso). */
4062  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4063  if (!uvedit_face_visible_test(scene, efa)) {
4064  continue;
4065  }
4066  BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
4067  MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
4068 
4069  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
4070  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4072  region, &rect, mcoords, mcoords_len, luv->uv, luv_prev->uv)) {
4074  scene, em, l_prev, select, false, cd_loop_uv_offset);
4075  changed = true;
4076  }
4077  l_prev = l;
4078  luv_prev = luv;
4079  }
4080  }
4081  }
4082  }
4083  else { /* Vert Selection. */
4085 
4086  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4087  if (!uvedit_face_visible_test(scene, efa)) {
4088  continue;
4089  }
4090  bool has_selected = false;
4091  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
4092  if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
4093  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4095  region, &rect, mcoords, mcoords_len, luv->uv)) {
4096  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
4097  changed = true;
4099  has_selected = true;
4100  }
4101  }
4102  }
4103  if (has_selected && use_select_linked) {
4104  UvNearestHit hit = {
4105  .ob = obedit,
4106  .efa = efa,
4107  };
4108  uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false);
4109  }
4110  }
4111 
4112  if (ts->uv_sticky == SI_STICKY_VERTEX) {
4113  uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
4114  }
4115  }
4116 
4117  if (changed || use_pre_deselect) {
4118  changed_multi = true;
4119  if (ts->uv_flag & UV_SYNC_SELECTION) {
4121  }
4122  else {
4124  }
4126  }
4127  }
4128  MEM_freeN(objects);
4129 
4130  return changed_multi;
4131 }
4132 
4134 {
4135  int mcoords_len;
4136  const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
4137 
4138  if (mcoords) {
4139  const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
4140  bool changed = do_lasso_select_mesh_uv(C, mcoords, mcoords_len, sel_op);
4141  MEM_freeN((void *)mcoords);
4142 
4143  return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
4144  }
4145 
4146  return OPERATOR_PASS_THROUGH;
4147 }
4148 
4150 {
4151  ot->name = "Lasso Select UV";
4152  ot->description = "Select UVs using lasso selection";
4153  ot->idname = "UV_OT_select_lasso";
4154 
4160 
4161  /* flags */
4163 
4164  /* properties */
4167 }
4168 
4171 /* -------------------------------------------------------------------- */
4176 {
4178  const ToolSettings *ts = scene->toolsettings;
4179 
4180  /* Use this operator only in vertex mode, since it is not guaranteed that pinned vertices may
4181  * form higher selection states (like edges/faces/islands) in other modes. */
4182  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
4183  if (ts->uv_selectmode != UV_SELECT_VERTEX) {
4184  BKE_report(op->reports, RPT_ERROR, "Pinned vertices can be selected in Vertex Mode only");
4185  return OPERATOR_CANCELLED;
4186  }
4187  }
4188 
4190  ViewLayer *view_layer = CTX_data_view_layer(C);
4191  BMFace *efa;
4192  BMLoop *l;
4193  BMIter iter, liter;
4194  MLoopUV *luv;
4195 
4196  uint objects_len = 0;
4198  view_layer, ((View3D *)NULL), &objects_len);
4199 
4200  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4201  Object *obedit = objects[ob_index];
4202  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4203 
4204  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
4205  bool changed = false;
4206 
4207  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4208  if (!uvedit_face_visible_test(scene, efa)) {
4209  continue;
4210  }
4211 
4212  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
4213  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4214 
4215  if (luv->flag & MLOOPUV_PINNED) {
4216  uvedit_uv_select_enable(scene, em, l, false, cd_loop_uv_offset);
4217  changed = true;
4218  }
4219  }
4220  }
4221  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
4223  }
4224 
4225  if (changed) {
4227  }
4228  }
4229  MEM_freeN(objects);
4230 
4231  return OPERATOR_FINISHED;
4232 }
4233 
4235 {
4236  /* identifiers */
4237  ot->name = "Selected Pinned";
4238  ot->description = "Select all pinned UV vertices";
4239  ot->idname = "UV_OT_select_pinned";
4241 
4242  /* api callbacks */
4245 }
4246 
4249 /* -------------------------------------------------------------------- */
4253 BLI_INLINE uint overlap_hash(const void *overlap_v)
4254 {
4255  const BVHTreeOverlap *overlap = overlap_v;
4256 
4257  /* Designed to treat (A,B) and (B,A) as the same. */
4258  int x = overlap->indexA;
4259  int y = overlap->indexB;
4260  if (x > y) {
4261  SWAP(int, x, y);
4262  }
4263  return BLI_hash_int_2d(x, y);
4264 }
4265 
4266 BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
4267 {
4268  const BVHTreeOverlap *a = a_v;
4269  const BVHTreeOverlap *b = b_v;
4270  return !((a->indexA == b->indexA && a->indexB == b->indexB) ||
4271  (a->indexA == b->indexB && a->indexB == b->indexA));
4272 }
4273 
4277  float tri[3][2];
4278 };
4279 
4287 static bool overlap_tri_tri_uv_test(const float t1[3][2],
4288  const float t2[3][2],
4289  const float endpoint_bias)
4290 {
4291  float vi[2];
4292 
4293  /* Don't use 'isect_tri_tri_v2' here
4294  * because it's important to ignore overlap at end-points. */
4295  if (isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 ||
4296  isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 ||
4297  isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 ||
4298  isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 ||
4299  isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 ||
4300  isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 ||
4301  isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 ||
4302  isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1) {
4303  return true;
4304  }
4305 
4306  /* When none of the segments intersect, checking if either of the triangles corners
4307  * is inside the others is almost always sufficient to test if the two triangles intersect.
4308  *
4309  * However, the `endpoint_bias` on segment intersections causes _exact_ overlapping
4310  * triangles not to be detected.
4311  *
4312  * Resolve this problem at the small cost of calculating the triangle center, see T85508. */
4313  mid_v2_v2v2v2(vi, UNPACK3(t1));
4314  if (isect_point_tri_v2(vi, UNPACK3(t2)) != 0) {
4315  return true;
4316  }
4317  mid_v2_v2v2v2(vi, UNPACK3(t2));
4318  if (isect_point_tri_v2(vi, UNPACK3(t1)) != 0) {
4319  return true;
4320  }
4321 
4322  return false;
4323 }
4324 
4325 static int uv_select_overlap(bContext *C, const bool extend)
4326 {
4329  ViewLayer *view_layer = CTX_data_view_layer(C);
4330 
4331  uint objects_len = 0;
4333  view_layer, ((View3D *)NULL), &objects_len);
4334 
4335  /* Calculate maximum number of tree nodes and prepare initial selection. */
4336  uint uv_tri_len = 0;
4337  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4338  Object *obedit = objects[ob_index];
4339  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4340 
4344  if (!extend) {
4346  }
4347 
4348  BMIter iter;
4349  BMFace *efa;
4350  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4352  continue;
4353  }
4354  uv_tri_len += efa->len - 2;
4355  }
4356  }
4357 
4358  struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len,
4359  "UvOverlapData");
4360  BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6);
4361 
4362  /* Use a global data index when inserting into the BVH. */
4363  int data_index = 0;
4364 
4365  int face_len_alloc = 3;
4366  float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords");
4367  uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris");
4368 
4369  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4370  Object *obedit = objects[ob_index];
4371  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4372  BMIter iter, liter;
4373  BMFace *efa;
4374  BMLoop *l;
4375 
4376  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
4377 
4378  /* Triangulate each UV face and store it inside the BVH. */
4379  int face_index;
4380  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
4381 
4383  continue;
4384  }
4385 
4386  const uint face_len = efa->len;
4387  const uint tri_len = face_len - 2;
4388 
4389  if (face_len_alloc < face_len) {
4390  MEM_freeN(uv_verts);
4391  MEM_freeN(indices);
4392  uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords");
4393  indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris");
4394  face_len_alloc = face_len;
4395  }
4396 
4397  int vert_index;
4398  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) {
4399  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4400  copy_v2_v2(uv_verts[vert_index], luv->uv);
4401  }
4402 
4403  BLI_polyfill_calc(uv_verts, face_len, 0, indices);
4404 
4405  for (int t = 0; t < tri_len; t++) {
4406  overlap_data[data_index].ob_index = ob_index;
4407  overlap_data[data_index].face_index = face_index;
4408 
4409  /* BVH needs 3D, overlap data uses 2D. */
4410  const float tri[3][3] = {
4411  {UNPACK2(uv_verts[indices[t][0]]), 0.0f},
4412  {UNPACK2(uv_verts[indices[t][1]]), 0.0f},
4413  {UNPACK2(uv_verts[indices[t][2]]), 0.0f},
4414  };
4415 
4416  copy_v2_v2(overlap_data[data_index].tri[0], tri[0]);
4417  copy_v2_v2(overlap_data[data_index].tri[1], tri[1]);
4418  copy_v2_v2(overlap_data[data_index].tri[2], tri[2]);
4419 
4420  BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3);
4421  data_index++;
4422  }
4423  }
4424  }
4425  BLI_assert(data_index == uv_tri_len);
4426 
4427  MEM_freeN(uv_verts);
4428  MEM_freeN(indices);
4429 
4430  BLI_bvhtree_balance(uv_tree);
4431 
4432  uint tree_overlap_len;
4433  BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL);
4434 
4435  if (overlap != NULL) {
4436  GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len);
4437 
4438  for (int i = 0; i < tree_overlap_len; i++) {
4439  /* Skip overlaps against yourself. */
4440  if (overlap[i].indexA == overlap[i].indexB) {
4441  continue;
4442  }
4443 
4444  /* Skip overlaps that have already been tested. */
4445  if (!BLI_gset_add(overlap_set, &overlap[i])) {
4446  continue;
4447  }
4448 
4449  const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA];
4450  const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB];
4451  Object *obedit_a = objects[o_a->ob_index];
4452  Object *obedit_b = objects[o_b->ob_index];
4453  BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a);
4454  BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b);
4455  BMFace *face_a = em_a->bm->ftable[o_a->face_index];
4456  BMFace *face_b = em_b->bm->ftable[o_b->face_index];
4457  const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV);
4458  const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV);
4459 
4460  /* Skip if both faces are already selected. */
4461  if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) &&
4462  uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) {
4463  continue;
4464  }
4465 
4466  /* Main tri-tri overlap test. */
4467  const float endpoint_bias = -1e-4f;
4468  if (overlap_tri_tri_uv_test(o_a->tri, o_b->tri, endpoint_bias)) {
4469  uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a);
4470  uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b);
4471  }
4472  }
4473 
4474  BLI_gset_free(overlap_set, NULL);
4475  MEM_freeN(overlap);
4476  }
4477 
4478  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4480  }
4481 
4482  BLI_bvhtree_free(uv_tree);
4483 
4484  MEM_freeN(overlap_data);
4485  MEM_freeN(objects);
4486 
4487  return OPERATOR_FINISHED;
4488 }
4489 
4491 {
4492  bool extend = RNA_boolean_get(op->ptr, "extend");
4493  return uv_select_overlap(C, extend);
4494 }
4495 
4497 {
4498  /* identifiers */
4499  ot->name = "Select Overlap";
4500  ot->description = "Select all UV faces which overlap each other";
4501  ot->idname = "UV_OT_select_overlap";
4503 
4504  /* api callbacks */
4507 
4508  /* properties */
4510  "extend",
4511  0,
4512  "Extend",
4513  "Extend selection rather than clearing the existing selection");
4514 }
4515 
4521  BMVert *vert,
4522  const float ob_m3[3][3],
4523  MLoopUV *luv,
4524  const int cd_loop_uv_offset)
4525 {
4526  float result = 0.0f;
4527  switch (type) {
4528  case UV_SSIM_AREA_UV: {
4529  BMFace *f;
4530  BMIter iter;
4531  BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) {
4532  result += BM_face_calc_area_uv(f, cd_loop_uv_offset);
4533  }
4534  } break;
4535  case UV_SSIM_AREA_3D: {
4536  BMFace *f;
4537  BMIter iter;
4538  BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) {
4539  result += BM_face_calc_area_with_mat3(f, ob_m3);
4540  }
4541  } break;
4542  case UV_SSIM_SIDES: {
4543  BMEdge *e;
4544  BMIter iter;
4545  BM_ITER_ELEM (e, &iter, vert, BM_EDGES_OF_VERT) {
4546  result += 1.0f;
4547  }
4548  } break;
4549  case UV_SSIM_PIN:
4550  return (luv->flag & MLOOPUV_PINNED) ? 1.0f : 0.0f;
4551  default:
4553  return false;
4554  }
4555 
4556  return result;
4557 }
4558 
4560  BMEdge *edge,
4561  const float ob_m3[3][3],
4562  MLoopUV *luv_a,
4563  MLoopUV *luv_b,
4564  const int cd_loop_uv_offset)
4565 {
4566  float result = 0.0f;
4567  switch (type) {
4568  case UV_SSIM_AREA_UV: {
4569  BMFace *f;
4570  BMIter iter;
4571  BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) {
4572  result += BM_face_calc_area_uv(f, cd_loop_uv_offset);
4573  }
4574  } break;
4575  case UV_SSIM_AREA_3D: {
4576  BMFace *f;
4577  BMIter iter;
4578  BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) {
4579  result += BM_face_calc_area_with_mat3(f, ob_m3);
4580  }
4581  } break;
4582  case UV_SSIM_LENGTH_UV:
4583  return len_v2v2(luv_a->uv, luv_b->uv);
4584  case UV_SSIM_LENGTH_3D:
4585  return len_v3v3(edge->v1->co, edge->v2->co);
4586  case UV_SSIM_SIDES: {
4587  BMEdge *e;
4588  BMIter iter;
4589  BM_ITER_ELEM (e, &iter, edge, BM_FACES_OF_EDGE) {
4590  result += 1.0f;
4591  }
4592  } break;
4593  case UV_SSIM_PIN:
4594  if (luv_a->flag & MLOOPUV_PINNED) {
4595  result += 1.0f;
4596  }
4597  if (luv_b->flag & MLOOPUV_PINNED) {
4598  result += 1.0f;
4599  }
4600  break;
4601  default:
4603  return false;
4604  }
4605 
4606  return result;
4607 }
4608 
4610  BMFace *face,
4611  const float ob_m3[3][3],
4612  const int cd_loop_uv_offset)
4613 {
4614  float result = 0.0f;
4615  switch (type) {
4616  case UV_SSIM_AREA_UV:
4617  return BM_face_calc_area_uv(face, cd_loop_uv_offset);
4618  case UV_SSIM_AREA_3D:
4619  return BM_face_calc_area_with_mat3(face, ob_m3);
4620  case UV_SSIM_SIDES:
4621  return face->len;
4622  case UV_SSIM_PIN: {
4623  BMLoop *l;
4624  BMIter liter;
4625  BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
4626  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4627  if (luv->flag & MLOOPUV_PINNED) {
4628  result += 1.0f;
4629  }
4630  }
4631  } break;
4632  case UV_SSIM_MATERIAL:
4633  return face->mat_nr;
4634  default:
4636  return false;
4637  }
4638  return result;
4639 }
4640 
4642 {
4644  ViewLayer *view_layer = CTX_data_view_layer(C);
4647 
4648  const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
4649  const float threshold = RNA_float_get(op->ptr, "threshold");
4650  const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
4651 
4652  uint objects_len = 0;
4654  view_layer, ((View3D *)NULL), &objects_len);
4655 
4656  int max_verts_selected_all = 0;
4657  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4658  Object *ob = objects[ob_index];
4660  BMFace *face;
4661  BMIter iter;
4662  BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
4663  if (!uvedit_face_visible_test(scene, face)) {
4664  continue;
4665  }
4666  max_verts_selected_all += face->len;
4667  }
4668  /* TODO: Get a tighter bounds */
4669  }
4670 
4671  int tree_index = 0;
4672  KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_verts_selected_all);
4673 
4674  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4675  Object *ob = objects[ob_index];
4677  BMesh *bm = em->bm;
4678  if (bm->totvertsel == 0) {
4679  continue;
4680  }
4681 
4682  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
4683  float ob_m3[3][3];
4684  copy_m3_m4(ob_m3, ob->obmat);
4685 
4686  BMFace *face;
4687  BMIter iter;
4688  BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
4689  if (!uvedit_face_visible_test(scene, face)) {
4690  continue;
4691  }
4692  BMLoop *l;
4693  BMIter liter;
4694  BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
4695  if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
4696  continue;
4697  }
4698  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4699  float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset);
4700  BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
4701  }
4702  }
4703  }
4704 
4705  if (tree_1d != NULL) {
4706  BLI_kdtree_1d_deduplicate(tree_1d);
4707  BLI_kdtree_1d_balance(tree_1d);
4708  }
4709 
4710  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4711  Object *ob = objects[ob_index];
4713  BMesh *bm = em->bm;
4714  if (bm->totvertsel == 0) {
4715  continue;
4716  }
4717 
4718  bool changed = false;
4719  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
4720  float ob_m3[3][3];
4721  copy_m3_m4(ob_m3, ob->obmat);
4722 
4723  BMFace *face;
4724  BMIter iter;
4725  BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
4726  if (!uvedit_face_visible_test(scene, face)) {
4727  continue;
4728  }
4729  BMLoop *l;
4730  BMIter liter;
4731  BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
4732  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
4733  continue; /* Already selected. */
4734  }
4735  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4736  const float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset);
4737  bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
4738  if (select) {
4739  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
4740  changed = true;
4741  }
4742  }
4743  if (changed) {
4745  }
4746  }
4747  }
4748 
4749  MEM_SAFE_FREE(objects);
4750  BLI_kdtree_1d_free(tree_1d);
4751  return OPERATOR_FINISHED;
4752 }
4753 
4755 {
4757  ViewLayer *view_layer = CTX_data_view_layer(C);
4760 
4761  const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
4762  const float threshold = RNA_float_get(op->ptr, "threshold");
4763  const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
4764 
4765  uint objects_len = 0;
4767  view_layer, ((View3D *)NULL), &objects_len);
4768 
4769  int max_edges_selected_all = 0;
4770  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4771  Object *ob = objects[ob_index];
4773  BMFace *face;
4774  BMIter iter;
4775  BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
4776  if (!uvedit_face_visible_test(scene, face)) {
4777  continue;
4778  }
4779  max_edges_selected_all += face->len;
4780  }
4781  /* TODO: Get a tighter bounds. */
4782  }
4783 
4784  int tree_index = 0;
4785  KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_edges_selected_all);
4786 
4787  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4788  Object *ob = objects[ob_index];
4790  BMesh *bm = em->bm;
4791  if (bm->totvertsel == 0) {
4792  continue;
4793  }
4794 
4795  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
4796  float ob_m3[3][3];
4797  copy_m3_m4(ob_m3, ob->obmat);
4798 
4799  BMFace *face;
4800  BMIter iter;
4801  BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
4802  if (!uvedit_face_visible_test(scene, face)) {
4803  continue;
4804  }
4805  BMLoop *l;
4806  BMIter liter;
4807  BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
4808  if (!uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
4809  continue;
4810  }
4811 
4812  MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4813  MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
4814  float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset);
4815  if (tree_1d) {
4816  BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
4817  }
4818  }
4819  }
4820  }
4821 
4822  if (tree_1d != NULL) {
4823  BLI_kdtree_1d_deduplicate(tree_1d);
4824  BLI_kdtree_1d_balance(tree_1d);
4825  }
4826 
4827  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4828  Object *ob = objects[ob_index];
4830  BMesh *bm = em->bm;
4831  if (bm->totvertsel == 0) {
4832  continue;
4833  }
4834 
4835  bool changed = false;
4836  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
4837  float ob_m3[3][3];
4838  copy_m3_m4(ob_m3, ob->obmat);
4839 
4840  BMFace *face;
4841  BMIter iter;
4842  BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
4843  if (!uvedit_face_visible_test(scene, face)) {
4844  continue;
4845  }
4846  BMLoop *l;
4847  BMIter liter;
4848  BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
4849  if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
4850  continue; /* Already selected. */
4851  }
4852 
4853  MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4854  MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
4855  float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset);
4856  bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
4857  if (select) {
4858  uvedit_edge_select_set(scene, em, l, select, false, cd_loop_uv_offset);
4859  changed = true;
4860  }
4861  }
4862  if (changed) {
4864  }
4865  }
4866  }
4867 
4868  MEM_SAFE_FREE(objects);
4869  BLI_kdtree_1d_free(tree_1d);
4870  return OPERATOR_FINISHED;
4871 }
4872 
4874 {
4876  ViewLayer *view_layer = CTX_data_view_layer(C);
4879 
4880  const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
4881  const float threshold = RNA_float_get(op->ptr, "threshold");
4882  const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
4883 
4884  uint objects_len = 0;
4886  view_layer, ((View3D *)NULL), &objects_len);
4887 
4888  int max_faces_selected_all = 0;
4889  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4890  Object *ob = objects[ob_index];
4892  max_faces_selected_all += em->bm->totfacesel;
4893  /* TODO: Get a tighter bounds */
4894  }
4895 
4896  int tree_index = 0;
4897  KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_faces_selected_all);
4898 
4899  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4900  Object *ob = objects[ob_index];
4901 
4903  BMesh *bm = em->bm;
4904 
4905  float ob_m3[3][3];
4906  copy_m3_m4(ob_m3, ob->obmat);
4907 
4908  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
4909 
4910  BMFace *face;
4911  BMIter iter;
4912  BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
4913  if (!uvedit_face_visible_test(scene, face)) {
4914  continue;
4915  }
4916  if (!uvedit_face_select_test(scene, face, cd_loop_uv_offset)) {
4917  continue;
4918  }
4919 
4920  float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset);
4921  if (tree_1d) {
4922  BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
4923  }
4924  }
4925  }
4926 
4927  if (tree_1d != NULL) {
4928  BLI_kdtree_1d_deduplicate(tree_1d);
4929  BLI_kdtree_1d_balance(tree_1d);
4930  }
4931 
4932  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4933  Object *ob = objects[ob_index];
4934 
4936  BMesh *bm = em->bm;
4937  bool changed = false;
4938  bool do_history = false;
4939  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
4940 
4941  float ob_m3[3][3];
4942  copy_m3_m4(ob_m3, ob->obmat);
4943 
4944  BMFace *face;
4945  BMIter iter;
4946  BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
4947  if (!uvedit_face_visible_test(scene, face)) {
4948  continue;
4949  }
4950  if (uvedit_face_select_test(scene, face, cd_loop_uv_offset)) {
4951  continue;
4952  }
4953 
4954  float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset);
4955 
4956  bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
4957  if (select) {
4958  uvedit_face_select_set(scene, em, face, select, do_history, cd_loop_uv_offset);
4959  changed = true;
4960  }
4961  }
4962  if (changed) {
4964  }
4965  }
4966 
4967  MEM_SAFE_FREE(objects);
4968  BLI_kdtree_1d_free(tree_1d);
4969  return OPERATOR_FINISHED;
4970 }
4971 
4972 /* Select similar UV faces/edges/verts based on current selection. */
4974 {
4976  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
4977 
4978  if (!RNA_property_is_set(op->ptr, prop)) {
4979  RNA_property_float_set(op->ptr, prop, ts->select_thresh);
4980  }
4981  else {
4982  ts->select_thresh = RNA_property_float_get(op->ptr, prop);
4983  }
4984 
4985  int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode;
4986  if (selectmode & UV_SELECT_EDGE) {
4987  return uv_select_similar_edge_exec(C, op);
4988  }
4989  if (selectmode & UV_SELECT_FACE) {
4990  return uv_select_similar_face_exec(C, op);
4991  }
4992  if (selectmode & UV_SELECT_ISLAND) {
4993  // return uv_select_similar_island_exec(C, op);
4994  }
4995 
4996  return uv_select_similar_vert_exec(C, op);
4997 }
4998 
4999 static EnumPropertyItem prop_vert_similar_types[] = {{UV_SSIM_PIN, "PIN", 0, "Pinned", ""}, {0}};
5000 
5002  {UV_SSIM_LENGTH_UV, "LENGTH", 0, "Length", ""},
5003  {UV_SSIM_LENGTH_3D, "LENGTH_3D", 0, "Length 3D", ""},
5004  {UV_SSIM_PIN, "PIN", 0, "Pinned", ""},
5005  {0}};
5006 
5008  {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""},
5009  {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""},
5010  {UV_SSIM_SIDES, "SIDES", 0, "Polygon Sides", ""},
5011  {UV_SSIM_MATERIAL, "MATERIAL", 0, "Material", ""},
5012  {0}};
5013 
5014 static EnumPropertyItem prop_similar_compare_types[] = {{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
5015  {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
5016  {SIM_CMP_LT, "LESS", 0, "Less", ""},
5017  {0}};
5018 
5020  PointerRNA *UNUSED(ptr),
5021  PropertyRNA *UNUSED(prop),
5022  bool *UNUSED(r_free))
5023 {
5024  const ToolSettings *ts = CTX_data_tool_settings(C);
5025  if (ts) {
5026  int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode;
5027  if (selectmode & UV_SELECT_EDGE) {
5028  return prop_edge_similar_types;
5029  }
5030  if (selectmode & UV_SELECT_FACE) {
5031  return prop_face_similar_types;
5032  }
5033  }
5034 
5035  return prop_vert_similar_types;
5036 }
5038 {
5039  /* identifiers */
5040  ot->name = "Select Similar";
5041  ot->description = "Select similar UVs by property types";
5042  ot->idname = "UV_OT_select_similar";
5043 
5044  /* api callbacks */
5048 
5049  /* flags */
5051 
5052  /* properties */
5053  PropertyRNA *prop = ot->prop = RNA_def_enum(
5054  ot->srna, "type", prop_vert_similar_types, SIMVERT_NORMAL, "Type", "");
5056  RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
5057  RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
5058 }
5059 
5062 /* -------------------------------------------------------------------- */
5069 BMFace **ED_uvedit_selected_faces(const Scene *scene, BMesh *bm, int len_max, int *r_faces_len)
5070 {
5071  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
5072  CLAMP_MAX(len_max, bm->totface);
5073  int faces_len = 0;
5074  BMFace **faces = MEM_mallocN(sizeof(*faces) * len_max, __func__);
5075 
5076  BMIter iter;
5077  BMFace *f;
5078  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
5079  if (uvedit_face_visible_test(scene, f)) {
5080  if (uvedit_face_select_test(scene, f, cd_loop_uv_offset)) {
5081  faces[faces_len++] = f;
5082  if (faces_len == len_max) {
5083  goto finally;
5084  }
5085  }
5086  }
5087  }
5088 
5089 finally:
5090  *r_faces_len = faces_len;
5091  if (faces_len != len_max) {
5092  faces = MEM_reallocN(faces, sizeof(*faces) * faces_len);
5093  }
5094  return faces;
5095 }
5096 
5097 BMLoop **ED_uvedit_selected_edges(const Scene *scene, BMesh *bm, int len_max, int *r_edges_len)
5098 {
5099  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
5100  CLAMP_MAX(len_max, bm->totloop);
5101  int edges_len = 0;
5102  BMLoop **edges = MEM_mallocN(sizeof(*edges) * len_max, __func__);
5103 
5104  BMIter iter;
5105  BMFace *f;
5106 
5107  /* Clear tag. */
5108  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
5109  BMIter liter;
5110  BMLoop *l_iter;
5111  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
5113  }
5114  }
5115 
5116  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
5117  if (uvedit_face_visible_test(scene, f)) {
5118  BMIter liter;
5119  BMLoop *l_iter;
5120  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
5121  if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
5122  if (uvedit_edge_select_test(scene, l_iter, cd_loop_uv_offset)) {
5124 
5125  edges[edges_len++] = l_iter;
5126  if (edges_len == len_max) {
5127  goto finally;
5128  }
5129 
5130  /* Tag other connected loops so we don't consider them separate edges. */
5131  if (l_iter != l_iter->radial_next) {
5132  BMLoop *l_radial_iter = l_iter->radial_next;
5133  do {
5134  if (BM_loop_uv_share_edge_check(l_iter, l_radial_iter, cd_loop_uv_offset)) {
5135  BM_elem_flag_enable(l_radial_iter, BM_ELEM_TAG);
5136  }
5137  } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
5138  }
5139  }
5140  }
5141  }
5142  }
5143  }
5144 
5145 finally:
5146  *r_edges_len = edges_len;
5147  if (edges_len != len_max) {
5148  edges = MEM_reallocN(edges, sizeof(*edges) * edges_len);
5149  }
5150  return edges;
5151 }
5152 
5153 BMLoop **ED_uvedit_selected_verts(const Scene *scene, BMesh *bm, int len_max, int *r_verts_len)
5154 {
5155  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
5156  CLAMP_MAX(len_max, bm->totloop);
5157  int verts_len = 0;
5158  BMLoop **verts = MEM_mallocN(sizeof(*verts) * len_max, __func__);
5159 
5160  BMIter iter;
5161  BMFace *f;
5162 
5163  /* Clear tag. */
5164  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
5165  BMIter liter;
5166  BMLoop *l_iter;
5167  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
5169  }
5170  }
5171 
5172  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
5173  if (uvedit_face_visible_test(scene, f)) {
5174  BMIter liter;
5175  BMLoop *l_iter;
5176  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
5177  if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
5178  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
5179  if (luv->flag & MLOOPUV_VERTSEL) {
5180  BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
5181 
5182  verts[verts_len++] = l_iter;
5183  if (verts_len == len_max) {
5184  goto finally;
5185  }
5186 
5187  /* Tag other connected loops so we don't consider them separate vertices. */
5188  BMIter liter_disk;
5189  BMLoop *l_disk_iter;
5190  BM_ITER_ELEM (l_disk_iter, &liter_disk, l_iter->v, BM_LOOPS_OF_VERT) {
5191  if (BM_loop_uv_share_vert_check(l_iter, l_disk_iter, cd_loop_uv_offset)) {
5192  BM_elem_flag_enable(l_disk_iter, BM_ELEM_TAG);
5193  }
5194  }
5195  }
5196  }
5197  }
5198  }
5199  }
5200 
5201 finally:
5202  *r_verts_len = verts_len;
5203  if (verts_len != len_max) {
5204  verts = MEM_reallocN(verts, sizeof(*verts) * verts_len);
5205  }
5206  return verts;
5207 }
5208 
5211 /* -------------------------------------------------------------------- */
5220  BMEditMesh *em,
5221  const int cd_loop_uv_offset)
5222 {
5224  BMFace *efa;
5225  BMIter iter, liter;
5226  UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true);
5227  if (elementmap == NULL) {
5228  return;
5229  }
5230 
5231  int num_islands = elementmap->totalIslands;
5232  /* Boolean array that tells if island with index i is completely selected or not. */
5233  bool *is_island_not_selected = MEM_callocN(sizeof(bool) * (num_islands), __func__);
5234 
5235  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
5236  BMLoop *l;
5237  if (!uvedit_face_visible_test(scene, efa)) {
5239  continue;
5240  }
5242  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
5243  if (!uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
5244  UvElement *element = BM_uv_element_get(elementmap, efa, l);
5245  is_island_not_selected[element->island] = true;
5246  }
5247  }
5248  }
5249 
5250  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
5251  BMLoop *l;
5252  if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) {
5253  continue;
5254  }
5255  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
5256  UvElement *element = BM_uv_element_get(elementmap, efa, l);
5257  /* Deselect all elements of islands which are not completely selected. */
5258  if (is_island_not_selected[element->island] == true) {
5259  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
5260  luv->flag &= ~(MLOOPUV_VERTSEL | MLOOPUV_EDGESEL);
5261  }
5262  }
5263  }
5264 
5265  BM_uv_element_map_free(elementmap);
5266  MEM_freeN(is_island_not_selected);
5267 }
5268 
5270 {
5271  const ToolSettings *ts = scene->toolsettings;
5272  BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0);
5273  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5274  char sticky = ts->uv_sticky;
5275  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
5276  BMFace *efa;
5277  BMLoop *l;
5278  BMIter iter, liter;
5279 
5280  if (ts->uv_selectmode == UV_SELECT_VERTEX) {
5281  /* Vertex mode. */
5282  if (sticky != SI_STICKY_DISABLE) {
5283  bm_loop_tags_clear(em->bm);
5284  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
5285  if (!uvedit_face_visible_test(scene, efa)) {
5286  continue;
5287  }
5288  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
5289  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
5291  }
5292  }
5293  }
5294  uv_select_flush_from_tag_loop(scene, obedit, true);
5295  }
5296  }
5297 
5298  else if (ts->uv_selectmode == UV_SELECT_EDGE) {
5299  /* Edge mode. */
5300  if (sticky != SI_STICKY_DISABLE) {
5301  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
5302  if (!uvedit_face_visible_test(scene, efa)) {
5303  continue;
5304  }
5305  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
5306  if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
5307  uvedit_edge_select_set_noflush(scene, l, true, sticky, cd_loop_uv_offset);
5308  }
5309  }
5310  }
5311  }
5313  }
5314 
5315  else if (ts->uv_selectmode == UV_SELECT_FACE) {
5316  /* Face mode. */
5317  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
5319  if (uvedit_face_visible_test(scene, efa)) {
5320  if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
5322  }
5323  uvedit_face_select_set(scene, em, efa, false, false, cd_loop_uv_offset);
5324  }
5325  }
5326  uv_select_flush_from_tag_face(scene, obedit, true);
5327  }
5328 
5329  else if (ts->uv_selectmode == UV_SELECT_ISLAND) {
5330  /* Island mode. */
5331  uv_isolate_selected_islands(scene, em, cd_loop_uv_offset);
5332  }
5333 
5335 }
5336 
5338 {
5340  ViewLayer *view_layer = CTX_data_view_layer(C);
5342 
5343  uint objects_len = 0;
5345  view_layer, ((View3D *)NULL), &objects_len);
5346 
5347  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5348  Object *obedit = objects[ob_index];
5350 
5352  }
5353  MEM_freeN(objects);
5354 }
5355 
5357 {
5360  const char new_uv_selectmode = RNA_enum_get(op->ptr, "type");
5361 
5362  /* Early exit if no change in current selection mode */
5363  if (new_uv_selectmode == ts->uv_selectmode) {
5364  return OPERATOR_CANCELLED;
5365  }
5366 
5367  /* Set new UV select mode. */
5368  ts->uv_selectmode = new_uv_selectmode;
5369 
5370  /* Handle UV selection states according to new select mode and sticky mode. */
5372 
5375 
5376  return OPERATOR_FINISHED;
5377 }
5378 
5379 static int uv_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
5380 {
5381  const ToolSettings *ts = CTX_data_tool_settings(C);
5382  const SpaceImage *sima = CTX_wm_space_image(C);
5383 
5384  /* Could be removed? - Already done in poll callback. */
5385  if ((!sima) || (sima->mode != SI_MODE_UV)) {
5386  return OPERATOR_CANCELLED;
5387  }
5388  /* Pass through when UV sync selection is enabled.
5389  * Allow for mesh select-mode key-map. */
5390  if (ts->uv_flag & UV_SYNC_SELECTION) {
5391  return OPERATOR_PASS_THROUGH;
5392  }
5393 
5394  return uv_select_mode_exec(C, op);
5395 }
5396 
5398 {
5399  /* identifiers */
5400  ot->name = "UV Select Mode";
5401  ot->description = "Change UV selection mode";
5402  ot->idname = "UV_OT_select_mode";
5403 
5404  /* api callbacks */
5408 
5409  /* flags */
5411 
5412  /* RNA props */
5413  PropertyRNA *prop;
5414  ot->prop = prop = RNA_def_enum(
5415  ot->srna, "type", rna_enum_mesh_select_mode_uv_items, 0, "Type", "");
5417 }
5418 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:824
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1282
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const struct CustomData *data, int type)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:550
General operations, lookup, etc. for materials.
void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode)
@ BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
struct GSet GSet
Definition: BLI_ghash.h:340
GSet * BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:939
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1037
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:969
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
Definition: BLI_hash.h:53
BVHTreeOverlap * BLI_bvhtree_overlap(const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_num, BVHTree_OverlapCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1363
void BLI_bvhtree_balance(BVHTree *tree)
Definition: BLI_kdopbvh.c:937
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
Definition: BLI_kdopbvh.c:854
void BLI_bvhtree_free(BVHTree *tree)
Definition: BLI_kdopbvh.c:926
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
Definition: BLI_kdopbvh.c:979
A KD-tree for nearest neighbor search.
bool BLI_lasso_is_point_inside(const int mcoords[][2], unsigned int mcoords_len, int sx, int sy, int error_value)
Definition: lasso_2d.c:38
void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], unsigned int mcoords_len)
Definition: lasso_2d.c:15
bool BLI_lasso_is_edge_inside(const int mcoords[][2], unsigned int mcoords_len, int x0, int y0, int x1, int y1, int error_value)
Definition: lasso_2d.c:52
MINLINE float square_f(float a)
float closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:357
int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2])
Definition: math_geom.c:1516
int isect_seg_seg_v2_point_ex(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float endpoint_bias, float vi[2])
Definition: math_geom.c:1195
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:283
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
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 void mul_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void mul_v2_v2(float r[2], const float a[2])
void mid_v2_v2v2v2(float v[2], const float v1[2], const float v2[2], const float v3[2])
Definition: math_vector.c:250
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void BLI_polyfill_calc(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3])
Definition: polyfill_2d.c:875
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
bool BLI_rcti_isect_segment(const struct rcti *rect, const int s1[2], const int s2[2])
bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const float s2[2])
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNPACK2(a)
#define CLAMP_MAX(a, c)
#define ARRAY_SIZE(arr)
#define SWAP(type, a, b)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define UNPACK3(a)
#define ELEM(...)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ CD_MLOOPUV
@ MLOOPUV_PINNED
@ MLOOPUV_VERTSEL
@ MLOOPUV_EDGESEL
Object is a sort of wrapper for general info.
#define UV_SELECT_EDGE
#define UV_SELECT_FACE
#define SCE_SELECT_FACE
@ SI_STICKY_VERTEX
@ SI_STICKY_LOC
@ SI_STICKY_DISABLE
#define UV_SYNC_SELECTION
#define SCE_SELECT_VERTEX
#define UV_SELECT_ISLAND
#define UV_SELECT_VERTEX
#define SCE_SELECT_EDGE
@ SI_MODE_UV
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
void ED_space_image_get_zoom(struct SpaceImage *sima, const struct ARegion *region, float *r_zoomx, float *r_zoomy)
void ED_space_image_get_size(struct SpaceImage *sima, int *r_width, int *r_height)
Definition: image_edit.c:201
struct UvVertMap * BM_uv_vert_map_create(struct BMesh *bm, bool use_select, bool use_winding)
struct UvElementMap * BM_uv_element_map_create(struct BMesh *bm, const struct Scene *scene, bool uv_selected, bool use_winding, bool do_islands)
struct UvElement * BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l)
struct UvMapVert * BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v)
void EDBM_flag_enable_all(struct BMEditMesh *em, char hflag)
void EDBM_select_flush(struct BMEditMesh *em)
void EDBM_select_more(struct BMEditMesh *em, bool use_face_step)
void EDBM_flag_disable_all(struct BMEditMesh *em, char hflag)
void EDBM_select_toggle_all(struct BMEditMesh *em)
void EDBM_deselect_flush(struct BMEditMesh *em)
void EDBM_select_less(struct BMEditMesh *em, bool use_face_step)
void EDBM_select_swap(struct BMEditMesh *em)
void BM_uv_element_map_free(struct UvElementMap *element_map)
void EDBM_selectmode_flush(struct BMEditMesh *em)
void BM_uv_vert_map_free(struct UvVertMap *vmap)
bool ED_operator_uvedit_space_image(struct bContext *C)
Definition: screen_ops.c:564
bool ED_operator_uvedit(struct bContext *C)
Definition: screen_ops.c:557
eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first)
Definition: select_utils.c:59
void ED_select_pick_params_from_operator(struct PointerRNA *ptr, struct SelectPick_Params *params) ATTR_NONNULL(1
#define SEL_OP_USE_PRE_DESELECT(sel_op)
const char * ED_select_circle_get_name(struct wmOperatorType *ot, PointerRNA *ptr)
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
eSimilarCmp
@ SIM_CMP_LT
@ SIM_CMP_GT
@ SIM_CMP_EQ
void const char * ED_select_pick_get_name(struct wmOperatorType *ot, PointerRNA *ptr)
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree, float length, float thresh, eSimilarCmp compare)
eSelectOp
@ SEL_OP_ADD
@ SEL_OP_SUB
@ SEL_OP_SET
@ SEL_OP_AND
@ SEL_OP_XOR
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
void UI_view2d_scale_get(const struct View2D *v2d, float *r_x, float *r_y)
bool UI_view2d_view_to_region_segment_clip(const View2D *v2d, const float xy_a[2], const float xy_b[2], int r_region_a[2], int r_region_b[2]) ATTR_NONNULL()
Definition: view2d.cc:1749
void UI_view2d_view_to_region_fl(const struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL()
void UI_view2d_region_to_view_rctf(const struct View2D *v2d, const struct rctf *rect_src, struct rctf *rect_dst) ATTR_NONNULL()
bool UI_view2d_view_to_region_clip(const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL()
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 V2D_IS_CLIPPED
Definition: UI_view2d.h:25
@ OPTYPE_DEPENDS_ON_CURSOR
Definition: WM_types.h:184
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define NC_SCENE
Definition: WM_types.h:328
#define ND_TOOLSETTINGS
Definition: WM_types.h:397
#define ND_SPACE_IMAGE
Definition: WM_types.h:465
#define ND_SELECT
Definition: WM_types.h:455
#define NC_SPACE
Definition: WM_types.h:342
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
#define BM_DISK_EDGE_NEXT(e, v)
Definition: bmesh_class.h:625
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:13
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
#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_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_select_history_clear(BMesh *bm)
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_select_history_validate(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_active_face_set(BMesh *bm, BMFace *f)
#define BM_select_history_store_notest(bm, ele)
#define BM_select_history_store(bm, ele)
#define BM_select_history_remove(bm, ele)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:558
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:115
ATTR_WARN_UNUSED_RESULT const void * element
@ SIMVERT_NORMAL
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1115
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
Definition: bmesh_query.c:1100
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 BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
bool BM_loop_uv_share_vert_check(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)
void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2])
bool BM_face_uv_point_inside_test(const BMFace *f, const float co[2], const int cd_loop_uv_offset)
unsigned int U
Definition: btGjkEpa3.h:78
Scene scene
const Depsgraph * depsgraph
static float verts[][3]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ccl_gpu_kernel_postfix int ccl_global int * indices
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static char faces[256]
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
return ret
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2767
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
Definition: rna_access.c:2790
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:4992
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
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:3862
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3830
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[]
Definition: rna_scene.c:138
BMVert * v1
Definition: bmesh_class.h:122
BMVert * v2
Definition: bmesh_class.h:122
struct BMLoop * l
Definition: bmesh_class.h:128
struct BMesh * bm
Definition: BKE_editmesh.h:40
struct BMEditSelection * prev
Definition: bmesh_marking.h:10
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:267
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
int totfacesel
Definition: bmesh_class.h:298
ListBase selected
Definition: bmesh_class.h:356
int totvertsel
Definition: bmesh_class.h:298
int totloop
Definition: bmesh_class.h:297
int totedgesel
Definition: bmesh_class.h:298
CustomData ldata
Definition: bmesh_class.h:337
BMFace ** ftable
Definition: bmesh_class.h:323
int totface
Definition: bmesh_class.h:297
void * last
Definition: DNA_listBase.h:31
float obmat[4][4]
void * data
struct ToolSettings * toolsettings
float tri[3][2]
struct UvMapVert * next
unsigned int poly_index
struct BMLoop * l
Definition: uvedit_intern.h:27
struct Object * ob
Definition: uvedit_intern.h:24
float scale[2]
Definition: uvedit_intern.h:37
struct BMFace * efa
Definition: uvedit_intern.h:26
int mval[2]
Definition: WM_types.h:684
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
const char *(* get_name)(struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:960
struct ReportList * reports
struct PointerRNA * ptr
#define UV_NEAREST_HIT_INIT_MAX(v2d)
Definition: uvedit_intern.h:49
#define UV_NEAREST_HIT_INIT_DIST_PX(v2d, dist_px)
Definition: uvedit_intern.h:40
void UV_OT_select_all(wmOperatorType *ot)
bool uv_find_nearest_vert_multi(Scene *scene, Object **objects, const uint objects_len, float const co[2], const float penalty_dist, UvNearestHit *hit)
void UV_OT_select_edge_ring(wmOperatorType *ot)
static EnumPropertyItem prop_edge_similar_types[]
bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
static int uv_circle_select_is_edge_inside(const float uv_a[2], const float uv_b[2], const float offset[2], const float ellipse[2])
void ED_uvedit_selectmode_clean(const Scene *scene, Object *obedit)
void uvedit_edge_select_set_with_sticky(const Scene *scene, BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, const uint cd_loop_uv_offset)
static BMLoop * uvedit_loop_find_other_radial_loop_with_visible_face(const Scene *scene, BMLoop *l_src, const int cd_loop_uv_offset)
void uvedit_face_select_enable(const Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, const int cd_loop_uv_offset)
void uvedit_uv_select_shared_vert(const Scene *scene, BMEditMesh *em, BMLoop *l, const bool select, const int sticky_flag, const bool do_history, const int cd_loop_uv_offset)
#define SET_SELECTION(value)
void ED_uvedit_selectmode_clean_multi(bContext *C)
bool uv_find_nearest_face_multi(Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit)
static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene, BMEditMesh *em, UvVertMap *vmap, const uint efa_index, BMLoop *l, const bool select, const int cd_loop_uv_offset)
static int uv_select_edge_ring_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit)
static float get_uv_vert_needle(const eUVSelectSimilar type, BMVert *vert, const float ob_m3[3][3], MLoopUV *luv, const int cd_loop_uv_offset)
static EnumPropertyItem prop_vert_similar_types[]
static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
void uvedit_edge_select_disable(const Scene *scene, BMEditMesh *em, BMLoop *l, const int cd_loop_uv_offset)
static int uv_circle_select_exec(bContext *C, wmOperator *op)
bool uv_find_nearest_face_multi_ex(Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit, const bool only_in_face)
static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
static int uv_select_loop_exec(bContext *C, wmOperator *op)
BMLoop * uv_find_nearest_loop_from_vert(struct Scene *scene, struct Object *obedit, struct BMVert *v, const float co[2])
eUVSelectSimilar
Definition: uvedit_select.c:81
@ UV_SSIM_AREA_UV
Definition: uvedit_select.c:82
@ UV_SSIM_LENGTH_UV
Definition: uvedit_select.c:84
@ UV_SSIM_MATERIAL
Definition: uvedit_select.c:88
@ UV_SSIM_PIN
Definition: uvedit_select.c:87
@ UV_SSIM_LENGTH_3D
Definition: uvedit_select.c:85
@ UV_SSIM_AREA_3D
Definition: uvedit_select.c:83
@ UV_SSIM_SIDES
Definition: uvedit_select.c:86
static void bm_loop_tags_clear(BMesh *bm)
void UV_OT_select(wmOperatorType *ot)
void ED_uvedit_active_edge_loop_set(BMesh *bm, BMLoop *l)
void UV_OT_select_split(wmOperatorType *ot)
static float get_uv_face_needle(const eUVSelectSimilar type, BMFace *face, const float ob_m3[3][3], const int cd_loop_uv_offset)
static int uv_select_overlap(bContext *C, const bool extend)
static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
static void uv_select_all_perform_multi(const Scene *scene, Object **objects, const uint objects_len, int action)
void UV_OT_select_linked(wmOperatorType *ot)
static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
static int uv_select_edgeloop(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
void uvedit_deselect_flush(const Scene *scene, BMEditMesh *em)
static bool uv_mouse_select(bContext *C, const float co[2], const struct SelectPick_Params *params)
static bool uv_mouse_select_multi(bContext *C, Object **objects, uint objects_len, const float co[2], const struct SelectPick_Params *params)
BMLoop * uv_find_nearest_loop_from_edge(struct Scene *scene, struct Object *obedit, struct BMEdge *e, const float co[2])
eUVEdgeLoopBoundaryMode
@ UV_EDGE_LOOP_BOUNDARY_ALL
@ UV_EDGE_LOOP_BOUNDARY_LOOP
void uvedit_uv_select_disable(const Scene *scene, BMEditMesh *em, BMLoop *l, const int cd_loop_uv_offset)
static int uv_select_mode_exec(bContext *C, wmOperator *op)
BMLoop ** ED_uvedit_selected_verts(const Scene *scene, BMesh *bm, int len_max, int *r_verts_len)
static int uv_circle_select_is_point_inside(const float uv[2], const float offset[2], const float ellipse[2])
static void uv_select_all_perform(const Scene *scene, Object *obedit, int action)
BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
static int uv_box_select_exec(bContext *C, wmOperator *op)
static int uv_select_similar_exec(bContext *C, wmOperator *op)
char ED_uvedit_select_mode_get(const Scene *scene)
static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], const float penalty, UvNearestHit *hit)
#define NEIGHBORING_FACE_IS_SEL
static void uv_select_all_perform_multi_ex(const Scene *scene, Object **objects, const uint objects_len, int action, const Object *ob_exclude)
static int uv_select_similar_vert_exec(bContext *C, wmOperator *op)
void uvedit_uv_select_enable(const Scene *scene, BMEditMesh *em, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
static int uv_select_overlap_exec(bContext *C, wmOperator *op)
static void uv_select_edgeloop_double_side_tag(const Scene *scene, BMEditMesh *em, BMLoop *l_init_pair[2], const int cd_loop_uv_offset)
static void uv_select_edgeloop_single_side_tag(const Scene *scene, BMEditMesh *em, BMLoop *l_init, const int cd_loop_uv_offset, enum eUVEdgeLoopBoundaryMode boundary_mode, int r_count_by_select[2])
void UV_OT_select_circle(wmOperatorType *ot)
void uvedit_select_flush(const Scene *scene, BMEditMesh *em)
static int uv_select_linked_exec(bContext *C, wmOperator *op)
bool uv_find_nearest_vert(Scene *scene, Object *obedit, float const co[2], const float penalty_dist, UvNearestHit *hit)
static int uv_select_all_exec(bContext *C, wmOperator *op)
void UV_OT_select_mode(wmOperatorType *ot)
bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa)
void UV_OT_select_similar(wmOperatorType *ot)
static int uv_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static bool do_lasso_select_mesh_uv_is_edge_inside(const ARegion *region, const rcti *clip_rect, const int mcoords[][2], const int mcoords_len, const float co_test_a[2], const float co_test_b[2])
static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, const bool select)
void UV_OT_select_linked_pick(wmOperatorType *ot)
void UV_OT_select_more(wmOperatorType *ot)
void uvedit_edge_select_set_noflush(const Scene *scene, BMLoop *l, const bool select, const int sticky_flag, const int cd_loop_uv_offset)
void UV_OT_select_pinned(wmOperatorType *ot)
bool uvedit_vert_is_face_select_any_other(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, const bool select)
void ED_uvedit_selectmode_flush(const Scene *scene, BMEditMesh *em)
static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int uv_select_edgering(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
void uvedit_uv_select_set_with_sticky(const Scene *scene, BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, const uint cd_loop_uv_offset)
static void bm_uv_flag_clear(const Scene *scene, BMesh *bm, const int flag, const int cd_loop_uv_offset)
BMFace ** ED_uvedit_selected_faces(const Scene *scene, BMesh *bm, int len_max, int *r_faces_len)
void UV_OT_select_loop(wmOperatorType *ot)
static EnumPropertyItem prop_face_similar_types[]
bool uvedit_select_is_any_selected_multi(const Scene *scene, Object **objects, const uint objects_len)
BLI_INLINE uint overlap_hash(const void *overlap_v)
BMLoop ** ED_uvedit_selected_edges(const Scene *scene, BMesh *bm, int len_max, int *r_edges_len)
static int uv_select_pinned_exec(bContext *C, wmOperator *op)
static bool uvedit_nearest_uv(const Scene *scene, Object *obedit, const float co[2], const float scale[2], const bool ignore_selected, float *dist_sq, float r_uv[2])
bool uvedit_face_visible_test(const Scene *scene, BMFace *efa)
static BMLoop * bm_select_edgeloop_double_side_next(const Scene *scene, BMLoop *l_step, BMVert *v_from, const int cd_loop_uv_offset)
static bool do_lasso_select_mesh_uv(bContext *C, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
static void uv_select_flush_from_loop_edge_flag(const Scene *scene, BMEditMesh *em)
static int uv_select_similar_edge_exec(bContext *C, wmOperator *op)
bool uv_find_nearest_edge_multi(Scene *scene, Object **objects, const uint objects_len, const float co[2], const float penalty, UvNearestHit *hit)
BMLoop * ED_uvedit_active_edge_loop_get(BMesh *bm)
static int uv_select_similar_face_exec(bContext *C, wmOperator *op)
eUVLoopGenericType
@ UV_RING_SELECT
@ UV_LOOP_SELECT
static void uv_isolate_selected_islands(const Scene *scene, BMEditMesh *em, const int cd_loop_uv_offset)
static bool overlap_tri_tri_uv_test(const float t1[3][2], const float t2[3][2], const float endpoint_bias)
static BMLoop * bm_select_edgeloop_single_side_next(const Scene *scene, BMLoop *l_step, BMVert *v_from, const int cd_loop_uv_offset)
static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region, const rcti *clip_rect, const int mcoords[][2], const int mcoords_len, const float co_test[2])
#define CURR_FACE_IS_UNSEL
static int uv_select_edge_ring_exec(bContext *C, wmOperator *op)
static void uvedit_vertex_select_tagged(BMEditMesh *em, Scene *scene, bool select, int cd_loop_uv_offset)
static int uv_select_split_exec(bContext *C, wmOperator *op)
bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
void uvedit_edge_select_shared_vert(const Scene *scene, BMEditMesh *em, BMLoop *l, const bool select, const int sticky_flag, const bool do_history, const int cd_loop_uv_offset)
static int uv_select_more_less(bContext *C, const bool select)
static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void uv_select_all(const Scene *scene, BMEditMesh *em, bool select_all)
bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
const float * uvedit_first_selected_uv_from_vertex(Scene *scene, BMVert *eve, const int cd_loop_uv_offset)
static int uv_mouse_select_loop_generic(bContext *C, const float co[2], const bool extend, enum eUVLoopGenericType loop_type)
void uvedit_face_select_set(const Scene *scene, BMEditMesh *em, BMFace *efa, const bool select, const bool do_history, const int cd_loop_uv_offset)
bool uv_find_nearest_face_ex(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face)
static int uv_select_exec(bContext *C, wmOperator *op)
void UV_OT_select_overlap(wmOperatorType *ot)
bool ED_uvedit_nearest_uv_multi(const View2D *v2d, const Scene *scene, Object **objects, const uint objects_len, const int mval[2], const bool ignore_selected, float *dist_sq, float r_uv[2])
void UV_OT_select_lasso(wmOperatorType *ot)
void uvedit_face_select_set_with_sticky(const Scene *scene, BMEditMesh *em, BMFace *efa, const bool select, const bool do_history, const int cd_loop_uv_offset)
static BMLoop * uvedit_loop_find_other_boundary_loop_with_visible_face(const Scene *scene, BMLoop *l_edge, BMVert *v_pivot, const int cd_loop_uv_offset)
static EnumPropertyItem prop_similar_compare_types[]
static int uv_select_faceloop(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
void uvedit_edge_select_set(const Scene *scene, BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, const int cd_loop_uv_offset)
static void uv_select_linked_multi(Scene *scene, Object **objects, const uint objects_len, UvNearestHit *hit, const bool extend, bool deselect, const bool toggle, const bool select_faces)
bool uvedit_vert_is_edge_select_any_other(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
BMLoop * ED_uvedit_active_vert_loop_get(BMesh *bm)
void uvedit_edge_select_enable(const Scene *scene, BMEditMesh *em, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
bool uvedit_vert_is_all_other_faces_selected(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
void uvedit_face_select_shared_vert(const Scene *scene, BMEditMesh *em, BMFace *efa, const bool select, const bool do_history, const int cd_loop_uv_offset)
void uvedit_face_select_disable(const Scene *scene, BMEditMesh *em, BMFace *efa, const int cd_loop_uv_offset)
static int uv_lasso_select_exec(bContext *C, wmOperator *op)
static void uv_select_invert(const Scene *scene, BMEditMesh *em)
static float get_uv_edge_needle(const eUVSelectSimilar type, BMEdge *edge, const float ob_m3[3][3], MLoopUV *luv_a, MLoopUV *luv_b, const int cd_loop_uv_offset)
bool uvedit_select_is_any_selected(const Scene *scene, Object *obedit)
void ED_uvedit_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const bool select)
static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
void uvedit_uv_select_set(const Scene *scene, BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, const int cd_loop_uv_offset)
static const EnumPropertyItem * uv_select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
void UV_OT_select_less(wmOperatorType *ot)
void ED_uvedit_active_vert_loop_set(BMesh *bm, BMLoop *l)
Definition: uvedit_select.c:98
static int uv_mouse_select_loop_generic_multi(bContext *C, Object **objects, uint objects_len, const float co[2], const bool extend, enum eUVLoopGenericType loop_type)
void UV_OT_select_box(wmOperatorType *ot)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
bool WM_gesture_is_modal_first(const wmGesture *gesture)
Definition: wm_gesture.c:108
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_circle_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_lasso_cancel(bContext *C, wmOperator *op)
int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const int(* WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, int *r_mcoords_len))[2]
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
void WM_operator_properties_mouse_select(wmOperatorType *ot)
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static bool do_history(const char *name, ReportList *reports)
Definition: writefile.c:1269