Blender  V2.93
uvedit_select.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "DNA_image_types.h"
31 #include "DNA_meshdata_types.h"
32 #include "DNA_node_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_space_types.h"
36 
37 #include "BLI_alloca.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_hash.h"
40 #include "BLI_kdopbvh.h"
41 #include "BLI_lasso_2d.h"
42 #include "BLI_math.h"
43 #include "BLI_polyfill_2d.h"
44 #include "BLI_utildefines.h"
45 
46 #include "BKE_context.h"
47 #include "BKE_customdata.h"
48 #include "BKE_editmesh.h"
49 #include "BKE_layer.h"
50 #include "BKE_mesh.h"
51 #include "BKE_mesh_mapping.h"
52 #include "BKE_report.h"
53 
54 #include "DEG_depsgraph.h"
55 #include "DEG_depsgraph_query.h"
56 
57 #include "ED_image.h"
58 #include "ED_mesh.h"
59 #include "ED_screen.h"
60 #include "ED_select_utils.h"
61 #include "ED_uvedit.h"
62 
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65 
66 #include "WM_api.h"
67 #include "WM_types.h"
68 
69 #include "UI_view2d.h"
70 
71 #include "uvedit_intern.h"
72 
73 static void uv_select_all_perform(Scene *scene, Object *obedit, int action);
74 
76  Scene *scene, Object **objects, const uint objects_len, int action, const Object *ob_exclude);
78  Object **objects,
79  const uint objects_len,
80  int action);
81 
83  Scene *scene,
84  Object *obedit,
85  const bool select);
87  Scene *scene,
88  Object *obedit,
89  const bool select);
91  const ToolSettings *ts,
92  Object *obedit);
93 
94 /* -------------------------------------------------------------------- */
102 {
108 }
109 
111 {
113  if (ese && ese->prev) {
114  BMEditSelection *ese_prev = ese->prev;
115  if ((ese->htype == BM_VERT) && (ese_prev->htype == BM_FACE)) {
116  /* May be NULL. */
117  return BM_face_vert_share_loop((BMFace *)ese_prev->ele, (BMVert *)ese->ele);
118  }
119  }
120  return NULL;
121 }
122 
124 {
130 }
131 
133 {
135  if (ese && ese->prev) {
136  BMEditSelection *ese_prev = ese->prev;
137  if ((ese->htype == BM_EDGE) && (ese_prev->htype == BM_FACE)) {
138  /* May be NULL. */
139  return BM_face_edge_share_loop((BMFace *)ese_prev->ele, (BMEdge *)ese->ele);
140  }
141  }
142  return NULL;
143 }
144 
147 /* -------------------------------------------------------------------- */
156 {
157  const ToolSettings *ts = scene->toolsettings;
158  char uv_selectmode = UV_SELECT_VERTEX;
159 
160  if (ts->uv_flag & UV_SYNC_SELECTION) {
161  if (ts->selectmode & SCE_SELECT_VERTEX) {
162  uv_selectmode = UV_SELECT_VERTEX;
163  }
164  else if (ts->selectmode & SCE_SELECT_EDGE) {
165  uv_selectmode = UV_SELECT_EDGE;
166  }
167  else if (ts->selectmode & SCE_SELECT_FACE) {
168  uv_selectmode = UV_SELECT_FACE;
169  }
170  }
171  else {
172  if (ts->uv_selectmode & UV_SELECT_VERTEX) {
173  uv_selectmode = UV_SELECT_VERTEX;
174  }
175  else if (ts->uv_selectmode & UV_SELECT_EDGE) {
176  uv_selectmode = UV_SELECT_EDGE;
177  }
178  else if (ts->uv_selectmode & UV_SELECT_FACE) {
179  uv_selectmode = UV_SELECT_FACE;
180  }
181  }
182  return uv_selectmode;
183 }
184 
186 {
187  /* bmesh API handles flushing but not on de-select */
188  if (ts->uv_flag & UV_SYNC_SELECTION) {
189  if (ts->selectmode != SCE_SELECT_FACE) {
190  if (select == false) {
192  }
193  else {
194  EDBM_select_flush(em);
195  }
196  }
197 
198  if (select == false) {
200  }
201  }
202 }
203 
205  Scene *scene,
206  bool select,
207  int cd_loop_uv_offset)
208 {
209  BMFace *efa;
210  BMLoop *l;
211  BMIter iter, liter;
212 
213  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
214  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
215  if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
216  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
217  }
218  }
219  }
220 }
221 
223 {
224  if (ts->uv_flag & UV_SYNC_SELECTION) {
225  return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
226  }
228 }
230 {
232 }
233 
234 bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
235 {
236  if (ts->uv_flag & UV_SYNC_SELECTION) {
237  return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
238  }
239 
240  BMLoop *l;
241  MLoopUV *luv;
242  BMIter liter;
243 
244  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
245  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
246  if (!(luv->flag & MLOOPUV_VERTSEL)) {
247  return false;
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  const Scene *scene,
259  BMEditMesh *em,
260  BMFace *efa,
261  const bool select,
262  const bool do_history,
263  const int cd_loop_uv_offset)
264 {
265  const ToolSettings *ts = scene->toolsettings;
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 
271  BMLoop *l_iter, *l_first;
272  l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
273  do {
275  sima, scene, em, l_iter, select, do_history, cd_loop_uv_offset);
276  } while ((l_iter = l_iter->next) != l_first);
277 }
278 
279 void uvedit_face_select_set(const struct Scene *scene,
280  struct BMEditMesh *em,
281  struct BMFace *efa,
282  const bool select,
283  const bool do_history,
284  const int cd_loop_uv_offset)
285 {
286  if (select) {
287  uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
288  }
289  else {
290  uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
291  }
292 }
293 
295  BMEditMesh *em,
296  BMFace *efa,
297  const bool do_history,
298  const int cd_loop_uv_offset)
299 {
300  const ToolSettings *ts = scene->toolsettings;
301 
302  if (ts->uv_flag & UV_SYNC_SELECTION) {
303  BM_face_select_set(em->bm, efa, true);
304  if (do_history) {
305  BM_select_history_store(em->bm, (BMElem *)efa);
306  }
307  }
308  else {
309  BMLoop *l;
310  MLoopUV *luv;
311  BMIter liter;
312 
313  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
314  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
315  luv->flag |= MLOOPUV_VERTSEL;
316  }
317  }
318 }
319 
321  BMEditMesh *em,
322  BMFace *efa,
323  const int cd_loop_uv_offset)
324 {
325  const ToolSettings *ts = scene->toolsettings;
326 
327  if (ts->uv_flag & UV_SYNC_SELECTION) {
328  BM_face_select_set(em->bm, efa, false);
329  }
330  else {
331  BMLoop *l;
332  MLoopUV *luv;
333  BMIter liter;
334 
335  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
336  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
337  luv->flag &= ~MLOOPUV_VERTSEL;
338  }
339  }
340 }
341 
342 bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
343 {
344  if (ts->uv_flag & UV_SYNC_SELECTION) {
345  if (ts->selectmode & SCE_SELECT_FACE) {
347  }
348  if (ts->selectmode == SCE_SELECT_EDGE) {
350  }
351  return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
353  }
354 
355  MLoopUV *luv1, *luv2;
356 
357  luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
358  luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
359 
360  return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
361 }
362 bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
363 {
364  return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
365 }
366 
368  const Scene *scene,
369  BMEditMesh *em,
370  BMLoop *l,
371  const bool select,
372  const bool do_history,
373  const uint cd_loop_uv_offset)
374 {
375  const ToolSettings *ts = scene->toolsettings;
376  if (ts->uv_flag & UV_SYNC_SELECTION) {
377  uvedit_edge_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
378  return;
379  }
380 
381  uvedit_uv_select_set_with_sticky(sima, scene, em, l, select, do_history, cd_loop_uv_offset);
383  sima, scene, em, l->next, select, do_history, cd_loop_uv_offset);
384 }
385 
387  BMEditMesh *em,
388  BMLoop *l,
389  const bool select,
390  const bool do_history,
391  const int cd_loop_uv_offset)
392 
393 {
394  if (select) {
395  uvedit_edge_select_enable(scene, em, l, do_history, cd_loop_uv_offset);
396  }
397  else {
398  uvedit_edge_select_disable(scene, em, l, cd_loop_uv_offset);
399  }
400 }
401 
403  BMEditMesh *em,
404  BMLoop *l,
405  const bool do_history,
406  const int cd_loop_uv_offset)
407 
408 {
409  const ToolSettings *ts = scene->toolsettings;
410 
411  if (ts->uv_flag & UV_SYNC_SELECTION) {
412  if (ts->selectmode & SCE_SELECT_FACE) {
413  BM_face_select_set(em->bm, l->f, true);
414  }
415  else if (ts->selectmode & SCE_SELECT_EDGE) {
416  BM_edge_select_set(em->bm, l->e, true);
417  }
418  else {
419  BM_vert_select_set(em->bm, l->e->v1, true);
420  BM_vert_select_set(em->bm, l->e->v2, true);
421  }
422 
423  if (do_history) {
424  BM_select_history_store(em->bm, (BMElem *)l->e);
425  }
426  }
427  else {
428  MLoopUV *luv1, *luv2;
429 
430  luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
431  luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
432 
433  luv1->flag |= MLOOPUV_VERTSEL;
434  luv2->flag |= MLOOPUV_VERTSEL;
435  }
436 }
437 
439  BMEditMesh *em,
440  BMLoop *l,
441  const int cd_loop_uv_offset)
442 
443 {
444  const ToolSettings *ts = scene->toolsettings;
445 
446  if (ts->uv_flag & UV_SYNC_SELECTION) {
447  if (ts->selectmode & SCE_SELECT_FACE) {
448  BM_face_select_set(em->bm, l->f, false);
449  }
450  else if (ts->selectmode & SCE_SELECT_EDGE) {
451  BM_edge_select_set(em->bm, l->e, false);
452  }
453  else {
454  BM_vert_select_set(em->bm, l->e->v1, false);
455  BM_vert_select_set(em->bm, l->e->v2, false);
456  }
457  }
458  else {
459  MLoopUV *luv1, *luv2;
460 
461  luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
462  luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
463 
464  luv1->flag &= ~MLOOPUV_VERTSEL;
465  luv2->flag &= ~MLOOPUV_VERTSEL;
466  }
467 }
468 
469 bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
470 {
471  if (ts->uv_flag & UV_SYNC_SELECTION) {
472  if (ts->selectmode & SCE_SELECT_FACE) {
474  }
476  }
477 
478  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
479  return (luv->flag & MLOOPUV_VERTSEL) != 0;
480 }
481 bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
482 {
483  return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
484 }
485 
487  const Scene *scene,
488  BMEditMesh *em,
489  BMLoop *l,
490  const bool select,
491  const bool do_history,
492  const uint cd_loop_uv_offset)
493 {
494  const ToolSettings *ts = scene->toolsettings;
495  if (ts->uv_flag & UV_SYNC_SELECTION) {
496  uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
497  return;
498  }
499 
500  const int sticky = sima->sticky;
501  switch (sticky) {
502  case SI_STICKY_DISABLE: {
503  uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
504  break;
505  }
506  default: {
507  /* #SI_STICKY_VERTEX or #SI_STICKY_LOC. */
508  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
509  BMEdge *e_first, *e_iter;
510  e_first = e_iter = l->e;
511  do {
512  if (e_iter->l) {
513  BMLoop *l_radial_iter = e_iter->l;
514  do {
515  if (l_radial_iter->v == l->v) {
516  if (uvedit_face_visible_test(scene, l_radial_iter->f)) {
517  bool do_select = false;
518  if (sticky == SI_STICKY_VERTEX) {
519  do_select = true;
520  }
521  else {
522  const MLoopUV *luv_other = BM_ELEM_CD_GET_VOID_P(l_radial_iter,
523  cd_loop_uv_offset);
524  if (equals_v2v2(luv_other->uv, luv->uv)) {
525  do_select = true;
526  }
527  }
528 
529  if (do_select) {
531  scene, em, l_radial_iter, select, do_history, cd_loop_uv_offset);
532  }
533  }
534  }
535  } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l);
536  }
537  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != e_first);
538  }
539  }
540 }
541 
543  BMEditMesh *em,
544  BMLoop *l,
545  const bool select,
546  const bool do_history,
547  const int cd_loop_uv_offset)
548 {
549  if (select) {
550  uvedit_uv_select_enable(scene, em, l, do_history, cd_loop_uv_offset);
551  }
552  else {
553  uvedit_uv_select_disable(scene, em, l, cd_loop_uv_offset);
554  }
555 }
556 
558  BMEditMesh *em,
559  BMLoop *l,
560  const bool do_history,
561  const int cd_loop_uv_offset)
562 {
563  const ToolSettings *ts = scene->toolsettings;
564 
565  if (ts->uv_flag & UV_SYNC_SELECTION) {
566  if (ts->selectmode & SCE_SELECT_FACE) {
567  BM_face_select_set(em->bm, l->f, true);
568  }
569  else {
570  BM_vert_select_set(em->bm, l->v, true);
571  }
572 
573  if (do_history) {
574  BM_select_history_store(em->bm, (BMElem *)l->v);
575  }
576  }
577  else {
578  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
579  luv->flag |= MLOOPUV_VERTSEL;
580  }
581 }
582 
584  BMEditMesh *em,
585  BMLoop *l,
586  const int cd_loop_uv_offset)
587 {
588  const ToolSettings *ts = scene->toolsettings;
589 
590  if (ts->uv_flag & UV_SYNC_SELECTION) {
591  if (ts->selectmode & SCE_SELECT_FACE) {
592  BM_face_select_set(em->bm, l->f, false);
593  }
594  else {
595  BM_vert_select_set(em->bm, l->v, false);
596  }
597  }
598  else {
599  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
600  luv->flag &= ~MLOOPUV_VERTSEL;
601  }
602 }
603 
605  BMLoop *l_src,
606  const int cd_loop_uv_offset)
607 {
608  BMLoop *l_other = NULL;
609  BMLoop *l_iter = l_src->radial_next;
610  if (l_iter != l_src) {
611  do {
612  if (uvedit_face_visible_test(scene, l_iter->f) &&
613  BM_loop_uv_share_edge_check(l_src, l_iter, cd_loop_uv_offset)) {
614  /* Check UV's are contiguous. */
615  if (l_other == NULL) {
616  l_other = l_iter;
617  }
618  else {
619  /* Only use when there is a single alternative. */
620  l_other = NULL;
621  break;
622  }
623  }
624  } while ((l_iter = l_iter->radial_next) != l_src);
625  }
626  return l_other;
627 }
628 
630  BMLoop *l_edge,
631  BMVert *v_pivot,
632  const int cd_loop_uv_offset)
633 {
635  scene, l_edge, cd_loop_uv_offset) == NULL);
636 
637  BMLoop *l_step = l_edge;
638  l_step = (l_step->v == v_pivot) ? l_step->prev : l_step->next;
639  BMLoop *l_step_last = NULL;
640  do {
641  BLI_assert(BM_vert_in_edge(l_step->e, v_pivot));
642  l_step_last = l_step;
644  scene, l_step, cd_loop_uv_offset);
645  if (l_step) {
646  l_step = (l_step->v == v_pivot) ? l_step->prev : l_step->next;
647  }
648  } while (l_step != NULL);
649 
650  if (l_step_last != NULL) {
652  scene, l_step_last, cd_loop_uv_offset) == NULL);
653  }
654 
655  return l_step_last;
656 }
657 
660 /* -------------------------------------------------------------------- */
664 bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
665 {
666  BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f));
667  BMEditMesh *em = BKE_editmesh_from_object(obedit);
668  BMFace *efa;
669  BMLoop *l;
670  BMIter iter, liter;
671  MLoopUV *luv, *luv_next;
672  int i;
673  bool found = false;
674 
675  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
676 
678 
679  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
680  if (!uvedit_face_visible_test(scene, efa)) {
681  continue;
682  }
683  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
684  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
685  luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
686 
687  float delta[2];
688  closest_to_line_segment_v2(delta, co, luv->uv, luv_next->uv);
689 
690  sub_v2_v2(delta, co);
691  mul_v2_v2(delta, hit->scale);
692 
693  const float dist_test_sq = len_squared_v2(delta);
694 
695  if (dist_test_sq < hit->dist_sq) {
696  hit->ob = obedit;
697  hit->efa = efa;
698 
699  hit->l = l;
700 
701  hit->dist_sq = dist_test_sq;
702  found = true;
703  }
704  }
705  }
706  return found;
707 }
708 
710  Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit)
711 {
712  bool found = false;
713  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
714  Object *obedit = objects[ob_index];
715  if (uv_find_nearest_edge(scene, obedit, co, hit)) {
716  found = true;
717  }
718  }
719  return found;
720 }
721 
732  Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face)
733 {
734  BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f));
735  BMEditMesh *em = BKE_editmesh_from_object(obedit);
736  bool found = false;
737 
738  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
739 
740  BMIter iter;
741  BMFace *efa;
742 
743  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
744  if (!uvedit_face_visible_test(scene, efa)) {
745  continue;
746  }
747 
748  float cent[2];
749  BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
750 
751  float delta[2];
752  sub_v2_v2v2(delta, co, cent);
753  mul_v2_v2(delta, hit->scale);
754 
755  const float dist_test_sq = len_squared_v2(delta);
756 
757  if (dist_test_sq < hit->dist_sq) {
758 
759  if (only_in_face) {
760  if (!BM_face_uv_point_inside_test(efa, co, cd_loop_uv_offset)) {
761  continue;
762  }
763  }
764 
765  hit->ob = obedit;
766  hit->efa = efa;
767  hit->dist_sq = dist_test_sq;
768  found = true;
769  }
770  }
771  return found;
772 }
773 
774 bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
775 {
776  return uv_find_nearest_face_ex(scene, obedit, co, hit, false);
777 }
778 
780  Object **objects,
781  const uint objects_len,
782  const float co[2],
783  UvNearestHit *hit,
784  const bool only_in_face)
785 {
786  bool found = false;
787  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
788  Object *obedit = objects[ob_index];
789  if (uv_find_nearest_face_ex(scene, obedit, co, hit, only_in_face)) {
790  found = true;
791  }
792  }
793  return found;
794 }
795 
797  Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit)
798 {
799  return uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, hit, false);
800 }
801 
802 static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
803 {
804  const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
805  const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
806  const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
807 
808  return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
809  (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
810 }
811 
813  Scene *scene, Object *obedit, float const co[2], const float penalty_dist, UvNearestHit *hit)
814 {
815  BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f));
816  bool found = false;
817 
818  BMEditMesh *em = BKE_editmesh_from_object(obedit);
819  BMFace *efa;
820  BMIter iter;
821 
823 
824  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
825 
826  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
827  if (!uvedit_face_visible_test(scene, efa)) {
828  continue;
829  }
830 
831  BMIter liter;
832  BMLoop *l;
833  int i;
834  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
835  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
836 
837  float delta[2];
838 
839  sub_v2_v2v2(delta, co, luv->uv);
840  mul_v2_v2(delta, hit->scale);
841 
842  float dist_test_sq = len_squared_v2(delta);
843 
844  if ((penalty_dist != 0.0f) && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
845  dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty_dist);
846  }
847 
848  if (dist_test_sq <= hit->dist_sq) {
849  if (dist_test_sq == hit->dist_sq) {
850  if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
851  continue;
852  }
853  }
854 
855  hit->dist_sq = dist_test_sq;
856 
857  hit->ob = obedit;
858  hit->efa = efa;
859  hit->l = l;
860  found = true;
861  }
862  }
863  }
864 
865  return found;
866 }
867 
869  Object **objects,
870  const uint objects_len,
871  float const co[2],
872  const float penalty_dist,
873  UvNearestHit *hit)
874 {
875  bool found = false;
876  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
877  Object *obedit = objects[ob_index];
878  if (uv_find_nearest_vert(scene, obedit, co, penalty_dist, hit)) {
879  found = true;
880  }
881  }
882  return found;
883 }
884 
886  const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2])
887 {
888  BMEditMesh *em = BKE_editmesh_from_object(obedit);
889  BMIter iter;
890  BMFace *efa;
891  const float *uv_best = NULL;
892  float dist_best = *dist_sq;
893  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
894  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
895  if (!uvedit_face_visible_test(scene, efa)) {
896  continue;
897  }
898  BMLoop *l_iter, *l_first;
899  l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
900  do {
901  const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
902  const float dist_test = len_squared_v2v2(co, uv);
903  if (dist_best > dist_test) {
904  dist_best = dist_test;
905  uv_best = uv;
906  }
907  } while ((l_iter = l_iter->next) != l_first);
908  }
909 
910  if (uv_best != NULL) {
911  copy_v2_v2(r_uv, uv_best);
912  *dist_sq = dist_best;
913  return true;
914  }
915  return false;
916 }
917 
919  Object **objects,
920  const uint objects_len,
921  const float co[2],
922  float *dist_sq,
923  float r_uv[2])
924 {
925  bool found = false;
926  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
927  Object *obedit = objects[ob_index];
928  if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) {
929  found = true;
930  }
931  }
932  return found;
933 }
934 
937 /* -------------------------------------------------------------------- */
946  struct Object *obedit,
947  struct BMVert *v,
948  const float co[2])
949 {
950  BMEditMesh *em = BKE_editmesh_from_object(obedit);
951  const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
952 
953  BMIter liter;
954  BMLoop *l;
955  BMLoop *l_found = NULL;
956  float dist_best_sq = FLT_MAX;
957 
958  BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
959  if (!uvedit_face_visible_test(scene, l->f)) {
960  continue;
961  }
962 
963  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
964  const float dist_test_sq = len_squared_v2v2(co, luv->uv);
965  if (dist_test_sq < dist_best_sq) {
966  dist_best_sq = dist_test_sq;
967  l_found = l;
968  }
969  }
970  return l_found;
971 }
972 
974  struct Object *obedit,
975  struct BMEdge *e,
976  const float co[2])
977 {
978  BMEditMesh *em = BKE_editmesh_from_object(obedit);
979  const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
980 
981  BMIter eiter;
982  BMLoop *l;
983  BMLoop *l_found = NULL;
984  float dist_best_sq = FLT_MAX;
985 
986  BM_ITER_ELEM (l, &eiter, e, BM_LOOPS_OF_EDGE) {
987  if (!uvedit_face_visible_test(scene, l->f)) {
988  continue;
989  }
990  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
991  const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
992  const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
993  if (dist_test_sq < dist_best_sq) {
994  dist_best_sq = dist_test_sq;
995  l_found = l;
996  }
997  }
998  return l_found;
999 }
1000 
1003 /* -------------------------------------------------------------------- */
1013 };
1014 
1016  BMLoop *l_step,
1017  BMVert *v_from,
1018  const int cd_loop_uv_offset)
1019 {
1020  if (l_step->f->len == 4) {
1021  BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from);
1022  BMLoop *l_step_over = (v_from == l_step->v) ? l_step->next : l_step->prev;
1024  scene, l_step_over, cd_loop_uv_offset);
1025  if (l_step_over) {
1026  return (l_step_over->v == v_from_next) ? l_step_over->prev : l_step_over->next;
1027  }
1028  }
1029  return NULL;
1030 }
1031 
1033  BMLoop *l_step,
1034  BMVert *v_from,
1035  const int cd_loop_uv_offset)
1036 {
1037  BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from);
1039  scene, l_step, v_from_next, cd_loop_uv_offset);
1040 }
1041 
1042 /* TODO(campbell): support this in the BMesh API, as we have for clearing other types. */
1044 {
1045  BMIter iter;
1046  BMFace *f;
1047  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1048  BMIter liter;
1049  BMLoop *l_iter;
1050  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
1052  }
1053  }
1054 }
1055 
1060  BMEditMesh *em,
1061  BMLoop *l_init_pair[2],
1062  const int cd_loop_uv_offset)
1063 {
1064  bm_loop_tags_clear(em->bm);
1065 
1066  for (int side = 0; side < 2; side++) {
1067  BMLoop *l_step_pair[2] = {l_init_pair[0], l_init_pair[1]};
1068  BMVert *v_from = side ? l_step_pair[0]->e->v1 : l_step_pair[0]->e->v2;
1069  /* Disable since we start from the same edge. */
1070  BM_elem_flag_disable(l_step_pair[0], BM_ELEM_TAG);
1071  BM_elem_flag_disable(l_step_pair[1], BM_ELEM_TAG);
1072  while ((l_step_pair[0] != NULL) && (l_step_pair[1] != NULL)) {
1073  if (!uvedit_face_visible_test(scene, l_step_pair[0]->f) ||
1074  !uvedit_face_visible_test(scene, l_step_pair[1]->f) ||
1075  /* Check loops have not diverged. */
1077  scene, l_step_pair[0], cd_loop_uv_offset) != l_step_pair[1])) {
1078  break;
1079  }
1080 
1081  BLI_assert(l_step_pair[0]->e == l_step_pair[1]->e);
1082 
1083  BM_elem_flag_enable(l_step_pair[0], BM_ELEM_TAG);
1084  BM_elem_flag_enable(l_step_pair[1], BM_ELEM_TAG);
1085 
1086  BMVert *v_from_next = BM_edge_other_vert(l_step_pair[0]->e, v_from);
1087  /* Walk over both sides, ensure they keep on the same edge. */
1088  for (int i = 0; i < ARRAY_SIZE(l_step_pair); i++) {
1089  l_step_pair[i] = bm_select_edgeloop_double_side_next(
1090  scene, l_step_pair[i], v_from, cd_loop_uv_offset);
1091  }
1092 
1093  if ((l_step_pair[0] && BM_elem_flag_test(l_step_pair[0], BM_ELEM_TAG)) ||
1094  (l_step_pair[1] && BM_elem_flag_test(l_step_pair[1], BM_ELEM_TAG))) {
1095  break;
1096  }
1097  v_from = v_from_next;
1098  }
1099  }
1100 }
1101 
1109  BMEditMesh *em,
1110  BMLoop *l_init,
1111  const int cd_loop_uv_offset,
1112  enum eUVEdgeLoopBoundaryMode boundary_mode,
1113  int r_count_by_select[2])
1114 {
1115  if (r_count_by_select) {
1116  r_count_by_select[0] = r_count_by_select[1] = 0;
1117  }
1118 
1119  bm_loop_tags_clear(em->bm);
1120 
1121  for (int side = 0; side < 2; side++) {
1122  BMLoop *l_step = l_init;
1123  BMVert *v_from = side ? l_step->e->v1 : l_step->e->v2;
1124  /* Disable since we start from the same edge. */
1126  while (l_step != NULL) {
1127 
1128  if (!uvedit_face_visible_test(scene, l_step->f) ||
1129  /* Check the boundary is still a boundary. */
1131  scene, l_step, cd_loop_uv_offset) != NULL)) {
1132  break;
1133  }
1134 
1135  if (r_count_by_select != NULL) {
1136  r_count_by_select[uvedit_edge_select_test(scene, l_step, cd_loop_uv_offset)] += 1;
1137  /* Early exit when mixed could be optional if needed. */
1138  if (r_count_by_select[0] && r_count_by_select[1]) {
1139  r_count_by_select[0] = r_count_by_select[1] = -1;
1140  break;
1141  }
1142  }
1143 
1145 
1146  BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from);
1147  BMFace *f_step_prev = l_step->f;
1148 
1149  l_step = bm_select_edgeloop_single_side_next(scene, l_step, v_from, cd_loop_uv_offset);
1150 
1151  if (l_step && BM_elem_flag_test(l_step, BM_ELEM_TAG)) {
1152  break;
1153  }
1154  if (boundary_mode == UV_EDGE_LOOP_BOUNDARY_LOOP) {
1155  /* Don't allow walking over the face. */
1156  if (f_step_prev == l_step->f) {
1157  break;
1158  }
1159  }
1160  v_from = v_from_next;
1161  }
1162  }
1163 }
1164 
1166  SpaceImage *sima, Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
1167 {
1168  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1169  bool select;
1170 
1171  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1172 
1173  if (extend) {
1174  select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
1175  }
1176  else {
1177  select = true;
1178  }
1179 
1180  BMLoop *l_init_pair[2] = {
1181  hit->l,
1183  };
1184 
1185  /* When selecting boundaries, support cycling between selection modes. */
1187 
1188  /* Tag all loops that are part of the edge loop (select after).
1189  * This is done so we can */
1190  if (l_init_pair[1] == NULL) {
1191  int count_by_select[2];
1192  /* If the loops selected toggle the boundaries. */
1194  scene, em, l_init_pair[0], cd_loop_uv_offset, boundary_mode, count_by_select);
1195  if (count_by_select[!select] == 0) {
1196  boundary_mode = UV_EDGE_LOOP_BOUNDARY_ALL;
1197 
1198  /* If the boundary is selected, toggle back to the loop. */
1200  scene, em, l_init_pair[0], cd_loop_uv_offset, boundary_mode, count_by_select);
1201  if (count_by_select[!select] == 0) {
1202  boundary_mode = UV_EDGE_LOOP_BOUNDARY_LOOP;
1203  }
1204  }
1205  }
1206 
1207  if (l_init_pair[1] == NULL) {
1209  scene, em, l_init_pair[0], cd_loop_uv_offset, boundary_mode, NULL);
1210  }
1211  else {
1212  uv_select_edgeloop_double_side_tag(scene, em, l_init_pair, cd_loop_uv_offset);
1213  }
1214 
1215  /* Apply the selection. */
1216  if (!extend) {
1218  }
1219 
1220  /* Select all tagged loops. */
1221  {
1222  BMIter iter;
1223  BMFace *f;
1224  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
1225  BMIter liter;
1226  BMLoop *l_iter;
1227  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
1228  if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
1230  sima, scene, em, l_iter, select, false, cd_loop_uv_offset);
1231  }
1232  }
1233  }
1234  }
1235 
1236  return (select) ? 1 : -1;
1237 }
1238 
1241 /* -------------------------------------------------------------------- */
1246  const SpaceImage *sima, Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
1247 {
1248  const ToolSettings *ts = scene->toolsettings;
1249  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1250  const bool use_face_select = (ts->uv_flag & UV_SYNC_SELECTION) ?
1251  (ts->selectmode & SCE_SELECT_FACE) :
1252  (ts->uv_selectmode & UV_SELECT_FACE);
1253  bool select;
1254 
1255  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1256 
1257  if (!extend) {
1259  }
1260 
1262 
1263  if (extend) {
1264  select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
1265  }
1266  else {
1267  select = true;
1268  }
1269 
1270  BMLoop *l_pair[2] = {
1271  hit->l,
1273  };
1274 
1275  for (int side = 0; side < 2; side++) {
1276  BMLoop *l_step = l_pair[side];
1277  /* Disable since we start from the same edge. */
1279  while (l_step) {
1280  if (!uvedit_face_visible_test(scene, l_step->f)) {
1281  break;
1282  }
1283 
1284  if (use_face_select) {
1286  sima, scene, em, l_step->f, select, false, cd_loop_uv_offset);
1287  }
1288  else {
1290  sima, scene, em, l_step, select, false, cd_loop_uv_offset);
1291  }
1292 
1293  BM_elem_flag_enable(l_step->e, BM_ELEM_TAG);
1294  if (l_step->f->len == 4) {
1295  BMLoop *l_step_opposite = l_step->next->next;
1297  scene, l_step_opposite, cd_loop_uv_offset);
1298  if (l_step == NULL) {
1299  /* Ensure we touch the opposite edge if we cant walk over it. */
1300  l_step = l_step_opposite;
1301  }
1302  }
1303  else {
1304  l_step = NULL;
1305  }
1306 
1307  if (l_step && BM_elem_flag_test(l_step->e, BM_ELEM_TAG)) {
1308  break;
1309  }
1310  }
1311  }
1312 
1313  return (select) ? 1 : -1;
1314 }
1315 
1318 /* -------------------------------------------------------------------- */
1323  Object **objects,
1324  const uint objects_len,
1325  UvNearestHit *hit,
1326  const bool extend,
1327  bool deselect,
1328  const bool toggle,
1329  const bool select_faces)
1330 {
1331  const bool uv_sync_select = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
1332 
1333  /* loop over objects, or just use hit->ob */
1334  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1335  if (hit && ob_index != 0) {
1336  break;
1337  }
1338  Object *obedit = hit ? hit->ob : objects[ob_index];
1339 
1340  BMFace *efa;
1341  BMLoop *l;
1342  BMIter iter, liter;
1343  UvVertMap *vmap;
1344  UvMapVert *vlist, *iterv, *startv;
1345  int i, stacksize = 0, *stack;
1346  uint a;
1347  char *flag;
1348 
1349  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1350  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1351 
1352  BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
1353 
1354  /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
1355  * this made *every* projection split the island into front/back islands.
1356  * Keep 'use_winding' to false, see: T50970.
1357  *
1358  * Better solve this by having a delimit option for select-linked operator,
1359  * keeping island-select working as is. */
1360  vmap = BM_uv_vert_map_create(em->bm, !uv_sync_select, false);
1361 
1362  if (vmap == NULL) {
1363  continue;
1364  }
1365 
1366  stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
1367  flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
1368 
1369  if (hit == NULL) {
1370  /* Use existing selection */
1371  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1372  if (uvedit_face_visible_test(scene, efa)) {
1373  if (select_faces) {
1374  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1375  stack[stacksize] = a;
1376  stacksize++;
1377  flag[a] = 1;
1378  }
1379  }
1380  else {
1381  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1382  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1383  bool add_to_stack = true;
1384  if (uv_sync_select && !select_faces) {
1385  /* Special case, vertex/edge & sync select being enabled.
1386  *
1387  * Without this, a second linked select will 'grow' each time as each new
1388  * selection reaches the boundaries of islands that share vertices but not UV's.
1389  *
1390  * Rules applied here:
1391  * - This loops face isn't selected.
1392  * - The only other fully selected face is connected or,
1393  * - There are no connected fully selected faces UV-connected to this loop.
1394  */
1395  if (uvedit_face_select_test(scene, l->f, cd_loop_uv_offset)) {
1396  /* pass */
1397  }
1398  else {
1399  BMIter liter_other;
1400  BMLoop *l_other;
1401  BM_ITER_ELEM (l_other, &liter_other, l->v, BM_LOOPS_OF_VERT) {
1402  if ((l != l_other) &&
1403  !BM_loop_uv_share_vert_check(l, l_other, cd_loop_uv_offset) &&
1404  uvedit_face_select_test(scene, l_other->f, cd_loop_uv_offset)) {
1405  add_to_stack = false;
1406  break;
1407  }
1408  }
1409  }
1410  }
1411 
1412  if (add_to_stack) {
1413  stack[stacksize] = a;
1414  stacksize++;
1415  flag[a] = 1;
1416  break;
1417  }
1418  }
1419  }
1420  }
1421  }
1422  }
1423  }
1424  else {
1425  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1426  if (efa == hit->efa) {
1427  stack[stacksize] = a;
1428  stacksize++;
1429  flag[a] = 1;
1430  break;
1431  }
1432  }
1433  }
1434 
1435  while (stacksize > 0) {
1436 
1437  stacksize--;
1438  a = stack[stacksize];
1439 
1440  efa = BM_face_at_index(em->bm, a);
1441 
1442  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1443 
1444  /* make_uv_vert_map_EM sets verts tmp.l to the indices */
1445  vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
1446 
1447  startv = vlist;
1448 
1449  for (iterv = vlist; iterv; iterv = iterv->next) {
1450  if (iterv->separate) {
1451  startv = iterv;
1452  }
1453  if (iterv->poly_index == a) {
1454  break;
1455  }
1456  }
1457 
1458  for (iterv = startv; iterv; iterv = iterv->next) {
1459  if ((startv != iterv) && (iterv->separate)) {
1460  break;
1461  }
1462  if (!flag[iterv->poly_index]) {
1463  flag[iterv->poly_index] = 1;
1464  stack[stacksize] = iterv->poly_index;
1465  stacksize++;
1466  }
1467  }
1468  }
1469  }
1470 
1471  /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
1472  if ((toggle == true) && (extend == false) && (deselect == false)) {
1473  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1474  bool found_selected = false;
1475  if (!flag[a]) {
1476  continue;
1477  }
1478 
1479  if (select_faces) {
1481  found_selected = true;
1482  }
1483  }
1484  else {
1485  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1486  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1487  found_selected = true;
1488  break;
1489  }
1490  }
1491 
1492  if (found_selected) {
1493  deselect = true;
1494  break;
1495  }
1496  }
1497  }
1498  }
1499 
1500 #define SET_SELECTION(value) \
1501  if (select_faces) { \
1502  BM_face_select_set(em->bm, efa, value); \
1503  } \
1504  else { \
1505  uvedit_face_select_set(scene, em, efa, value, false, cd_loop_uv_offset); \
1506  } \
1507  (void)0
1508 
1509  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1510  if (!flag[a]) {
1511  if (!extend && !deselect && !toggle) {
1512  SET_SELECTION(false);
1513  }
1514  continue;
1515  }
1516 
1517  if (!deselect) {
1518  SET_SELECTION(true);
1519  }
1520  else {
1521  SET_SELECTION(false);
1522  }
1523  }
1524 
1525 #undef SET_SELECTION
1526 
1527  MEM_freeN(stack);
1528  MEM_freeN(flag);
1529  BM_uv_vert_map_free(vmap);
1530 
1531  if (uv_sync_select) {
1532  if (deselect) {
1533  EDBM_deselect_flush(em);
1534  }
1535  else {
1536  if (!select_faces) {
1538  }
1539  }
1540  }
1541  }
1542 }
1543 
1549  BMVert *eve,
1550  const int cd_loop_uv_offset)
1551 {
1552  BMIter liter;
1553  BMLoop *l;
1554 
1555  BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
1556  if (!uvedit_face_visible_test(scene, l->f)) {
1557  continue;
1558  }
1559 
1560  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1561  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1562  return luv->uv;
1563  }
1564  }
1565 
1566  return NULL;
1567 }
1568 
1571 /* -------------------------------------------------------------------- */
1575 static int uv_select_more_less(bContext *C, const bool select)
1576 {
1578  ViewLayer *view_layer = CTX_data_view_layer(C);
1579  SpaceImage *sima = CTX_wm_space_image(C);
1580 
1581  BMFace *efa;
1582  BMLoop *l;
1583  BMIter iter, liter;
1584  const ToolSettings *ts = scene->toolsettings;
1585 
1586  uint objects_len = 0;
1588  view_layer, ((View3D *)NULL), &objects_len);
1589 
1590  const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE);
1591 
1592  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1593  Object *obedit = objects[ob_index];
1594  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1595 
1596  bool changed = false;
1597 
1598  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1599 
1600  if (ts->uv_flag & UV_SYNC_SELECTION) {
1601  if (select) {
1602  EDBM_select_more(em, true);
1603  }
1604  else {
1605  EDBM_select_less(em, true);
1606  }
1607 
1610  continue;
1611  }
1612 
1613  if (is_uv_face_selectmode) {
1614 
1615  /* clear tags */
1617 
1618  /* mark loops to be selected */
1619  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1620  if (uvedit_face_visible_test(scene, efa)) {
1621 
1622 #define IS_SEL 1
1623 #define IS_UNSEL 2
1624 
1625  int sel_state = 0;
1626 
1627  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1628  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1629  if (luv->flag & MLOOPUV_VERTSEL) {
1630  sel_state |= IS_SEL;
1631  }
1632  else {
1633  sel_state |= IS_UNSEL;
1634  }
1635 
1636  /* if we have a mixed selection, tag to grow it */
1637  if (sel_state == (IS_SEL | IS_UNSEL)) {
1639  changed = true;
1640  break;
1641  }
1642  }
1643 
1644 #undef IS_SEL
1645 #undef IS_UNSEL
1646  }
1647  }
1648  }
1649  else {
1650 
1651  /* clear tags */
1652  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1653  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1655  }
1656  }
1657 
1658  /* mark loops to be selected */
1659  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1660  if (uvedit_face_visible_test(scene, efa)) {
1661  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1662 
1663  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1664 
1665  if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
1668  changed = true;
1669  }
1670  }
1671  }
1672  }
1673  }
1674 
1675  if (changed) {
1676  if (is_uv_face_selectmode) {
1677  /* Select tagged faces. */
1678  uv_select_flush_from_tag_face(sima, scene, obedit, select);
1679  }
1680  else {
1681  /* Select tagged loops. */
1682  uv_select_flush_from_tag_loop(sima, scene, obedit, select);
1683  }
1686  }
1687  }
1688  MEM_freeN(objects);
1689 
1690  return OPERATOR_FINISHED;
1691 }
1692 
1694 {
1695  return uv_select_more_less(C, true);
1696 }
1697 
1699 {
1700  /* identifiers */
1701  ot->name = "Select More";
1702  ot->description = "Select more UV vertices connected to initial selection";
1703  ot->idname = "UV_OT_select_more";
1705 
1706  /* api callbacks */
1709 }
1710 
1712 {
1713  return uv_select_more_less(C, false);
1714 }
1715 
1717 {
1718  /* identifiers */
1719  ot->name = "Select Less";
1720  ot->description = "Deselect UV vertices at the boundary of each selection region";
1721  ot->idname = "UV_OT_select_less";
1723 
1724  /* api callbacks */
1727 }
1728 
1731 /* -------------------------------------------------------------------- */
1736 {
1737  const ToolSettings *ts = scene->toolsettings;
1738  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1739  BMFace *efa;
1740  BMLoop *l;
1741  BMIter iter, liter;
1742  MLoopUV *luv;
1743 
1744  if (ts->uv_flag & UV_SYNC_SELECTION) {
1745  return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
1746  }
1747 
1748  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1749  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1750  if (!uvedit_face_visible_test(scene, efa)) {
1751  continue;
1752  }
1753  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1754  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1755  if (luv->flag & MLOOPUV_VERTSEL) {
1756  return true;
1757  }
1758  }
1759  }
1760  return false;
1761 }
1762 
1763 bool uvedit_select_is_any_selected_multi(Scene *scene, Object **objects, const uint objects_len)
1764 {
1765  bool found = false;
1766  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1767  Object *obedit = objects[ob_index];
1768  if (uvedit_select_is_any_selected(scene, obedit)) {
1769  found = true;
1770  break;
1771  }
1772  }
1773  return found;
1774 }
1775 
1776 static void uv_select_all_perform(Scene *scene, Object *obedit, int action)
1777 {
1778  const ToolSettings *ts = scene->toolsettings;
1779  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1780  BMFace *efa;
1781  BMLoop *l;
1782  BMIter iter, liter;
1783  MLoopUV *luv;
1784 
1785  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1786 
1787  if (action == SEL_TOGGLE) {
1789  }
1790 
1791  if (ts->uv_flag & UV_SYNC_SELECTION) {
1792  switch (action) {
1793  case SEL_TOGGLE:
1795  break;
1796  case SEL_SELECT:
1798  break;
1799  case SEL_DESELECT:
1801  break;
1802  case SEL_INVERT:
1803  EDBM_select_swap(em);
1805  break;
1806  }
1807  }
1808  else {
1809  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1810  if (!uvedit_face_visible_test(scene, efa)) {
1811  continue;
1812  }
1813 
1814  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1815  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1816 
1817  switch (action) {
1818  case SEL_SELECT:
1819  luv->flag |= MLOOPUV_VERTSEL;
1820  break;
1821  case SEL_DESELECT:
1822  luv->flag &= ~MLOOPUV_VERTSEL;
1823  break;
1824  case SEL_INVERT:
1825  luv->flag ^= MLOOPUV_VERTSEL;
1826  break;
1827  }
1828  }
1829  }
1830  }
1831 }
1832 
1834  Scene *scene, Object **objects, const uint objects_len, int action, const Object *ob_exclude)
1835 {
1836  if (action == SEL_TOGGLE) {
1837  action = uvedit_select_is_any_selected_multi(scene, objects, objects_len) ? SEL_DESELECT :
1838  SEL_SELECT;
1839  }
1840 
1841  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1842  Object *obedit = objects[ob_index];
1843  if (ob_exclude && (obedit == ob_exclude)) {
1844  continue;
1845  }
1846  uv_select_all_perform(scene, obedit, action);
1847  }
1848 }
1849 
1851  Object **objects,
1852  const uint objects_len,
1853  int action)
1854 {
1855  uv_select_all_perform_multi_ex(scene, objects, objects_len, action, NULL);
1856 }
1857 
1859 {
1862  const ToolSettings *ts = scene->toolsettings;
1863  ViewLayer *view_layer = CTX_data_view_layer(C);
1864 
1865  int action = RNA_enum_get(op->ptr, "action");
1866 
1867  uint objects_len = 0;
1869  view_layer, ((View3D *)NULL), &objects_len);
1870 
1871  uv_select_all_perform_multi(scene, objects, objects_len, action);
1872 
1873  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1874  Object *obedit = objects[ob_index];
1876  }
1877 
1878  MEM_freeN(objects);
1879 
1880  return OPERATOR_FINISHED;
1881 }
1882 
1884 {
1885  /* identifiers */
1886  ot->name = "(De)select All";
1887  ot->description = "Change selection of all UV vertices";
1888  ot->idname = "UV_OT_select_all";
1890 
1891  /* api callbacks */
1894 
1896 }
1897 
1900 /* -------------------------------------------------------------------- */
1905  Object **objects,
1906  uint objects_len,
1907  const float co[2],
1908  const bool extend,
1909  const bool deselect_all)
1910 {
1912  SpaceImage *sima = CTX_wm_space_image(C);
1913  const ARegion *region = CTX_wm_region(C);
1915  const ToolSettings *ts = scene->toolsettings;
1916  UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(&region->v2d, 75.0f);
1917  int selectmode, sticky;
1918  bool found_item = false;
1919  /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
1920  int flush = 0;
1921 
1922  /* Penalty (in pixels) applied to elements that are already selected
1923  * so elements that aren't already selected are prioritized. */
1924  const float penalty_dist = 3.0f * U.pixelsize;
1925 
1926  /* retrieve operation mode */
1927  if (ts->uv_flag & UV_SYNC_SELECTION) {
1928  if (ts->selectmode & SCE_SELECT_FACE) {
1929  selectmode = UV_SELECT_FACE;
1930  }
1931  else if (ts->selectmode & SCE_SELECT_EDGE) {
1932  selectmode = UV_SELECT_EDGE;
1933  }
1934  else {
1935  selectmode = UV_SELECT_VERTEX;
1936  }
1937 
1938  sticky = SI_STICKY_DISABLE;
1939  }
1940  else {
1941  selectmode = ts->uv_selectmode;
1942  sticky = (sima) ? sima->sticky : SI_STICKY_DISABLE;
1943  }
1944 
1945  /* find nearest element */
1946  if (selectmode == UV_SELECT_VERTEX) {
1947  /* find vertex */
1948  found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit);
1949  if (found_item) {
1950  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
1953  }
1954  }
1955  }
1956  else if (selectmode == UV_SELECT_EDGE) {
1957  /* find edge */
1958  found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
1959  if (found_item) {
1960  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
1963  }
1964  }
1965  }
1966  else if (selectmode == UV_SELECT_FACE) {
1967  /* find face */
1968  found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit);
1969 
1970  if (!found_item) {
1971  /* Fallback, perform a second pass without a limited threshold,
1972  * which succeeds as long as the cursor is inside the UV face.
1973  * Useful when zoomed in, to select faces with distant screen-space face centers. */
1974  hit.dist_sq = FLT_MAX;
1975  found_item = uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, &hit, true);
1976  }
1977 
1978  if (found_item) {
1981  }
1982  }
1983  else if (selectmode == UV_SELECT_ISLAND) {
1984  found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
1985 
1986  if (!found_item) {
1987  /* Without this, we can be within the face of an island but too far from an edge,
1988  * see face selection comment for details. */
1989  hit.dist_sq = FLT_MAX;
1990  found_item = uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, &hit, true);
1991  }
1992  }
1993 
1994  if (!found_item) {
1995  if (deselect_all) {
1996  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
1997 
1998  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1999  Object *obedit = objects[ob_index];
2001  }
2002 
2004  }
2005  return OPERATOR_CANCELLED;
2006  }
2007 
2008  Object *obedit = hit.ob;
2009  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2010  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2011 
2012  /* do selection */
2013  if (selectmode == UV_SELECT_ISLAND) {
2014  if (!extend) {
2015  uv_select_all_perform_multi_ex(scene, objects, objects_len, SEL_DESELECT, obedit);
2016  }
2017  /* Current behavior of 'extend'
2018  * is actually toggling, so pass extend flag as 'toggle' here */
2019  uv_select_linked_multi(scene, objects, objects_len, &hit, false, false, extend, false);
2020  }
2021  else if (extend) {
2022  bool select = true;
2023  if (selectmode == UV_SELECT_VERTEX) {
2024  /* (de)select uv vertex */
2025  select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
2026  uvedit_uv_select_set_with_sticky(sima, scene, em, hit.l, select, true, cd_loop_uv_offset);
2027  flush = 1;
2028  }
2029  else if (selectmode == UV_SELECT_EDGE) {
2030  /* (de)select edge */
2031  select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
2032  uvedit_edge_select_set_with_sticky(sima, scene, em, hit.l, select, true, cd_loop_uv_offset);
2033  flush = 1;
2034  }
2035  else if (selectmode == UV_SELECT_FACE) {
2036  /* (de)select face */
2037  select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
2039  sima, scene, em, hit.efa, select, true, cd_loop_uv_offset);
2040  flush = -1;
2041  }
2042 
2043  /* de-selecting an edge may deselect a face too - validate */
2044  if (ts->uv_flag & UV_SYNC_SELECTION) {
2045  if (select == false) {
2047  }
2048  }
2049 
2050  /* (de)select sticky uv nodes */
2051  if (sticky != SI_STICKY_DISABLE) {
2052  flush = select ? 1 : -1;
2053  }
2054  }
2055  else {
2056  const bool select = true;
2057  /* deselect all */
2058  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
2059 
2060  if (selectmode == UV_SELECT_VERTEX) {
2061  /* select vertex */
2062  uvedit_uv_select_set_with_sticky(sima, scene, em, hit.l, select, true, cd_loop_uv_offset);
2063  flush = 1;
2064  }
2065  else if (selectmode == UV_SELECT_EDGE) {
2066  /* select edge */
2067  uvedit_edge_select_set_with_sticky(sima, scene, em, hit.l, select, true, cd_loop_uv_offset);
2068  flush = 1;
2069  }
2070  else if (selectmode == UV_SELECT_FACE) {
2071  /* select face */
2073  sima, scene, em, hit.efa, select, true, cd_loop_uv_offset);
2074  flush = 1;
2075  }
2076  }
2077 
2078  if (ts->uv_flag & UV_SYNC_SELECTION) {
2079  if (flush != 0) {
2081  }
2082  }
2083 
2084  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2085  Object *obiter = objects[ob_index];
2087  }
2088 
2090 }
2092  const float co[2],
2093  const bool extend,
2094  const bool deselect_all)
2095 {
2096  ViewLayer *view_layer = CTX_data_view_layer(C);
2097  uint objects_len = 0;
2099  view_layer, ((View3D *)NULL), &objects_len);
2100  int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all);
2101  MEM_freeN(objects);
2102  return ret;
2103 }
2104 
2106 {
2107  float co[2];
2108 
2109  RNA_float_get_array(op->ptr, "location", co);
2110  const bool extend = RNA_boolean_get(op->ptr, "extend");
2111  const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
2112 
2113  return uv_mouse_select(C, co, extend, deselect_all);
2114 }
2115 
2116 static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2117 {
2118  const ARegion *region = CTX_wm_region(C);
2119  float co[2];
2120 
2121  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2122  RNA_float_set_array(op->ptr, "location", co);
2123 
2124  return uv_select_exec(C, op);
2125 }
2126 
2128 {
2129  /* identifiers */
2130  ot->name = "Select";
2131  ot->description = "Select UV vertices";
2132  ot->idname = "UV_OT_select";
2133  ot->flag = OPTYPE_UNDO;
2134 
2135  /* api callbacks */
2136  ot->exec = uv_select_exec;
2138  ot->poll = ED_operator_uvedit; /* requires space image */
2139 
2140  /* properties */
2141  PropertyRNA *prop;
2143  "extend",
2144  0,
2145  "Extend",
2146  "Extend selection rather than clearing the existing selection");
2147  prop = RNA_def_boolean(ot->srna,
2148  "deselect_all",
2149  false,
2150  "Deselect On Nothing",
2151  "Deselect all when nothing under the cursor");
2153 
2155  ot->srna,
2156  "location",
2157  2,
2158  NULL,
2159  -FLT_MAX,
2160  FLT_MAX,
2161  "Location",
2162  "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
2163  -100.0f,
2164  100.0f);
2165 }
2166 
2169 /* -------------------------------------------------------------------- */
2176 };
2177 
2179  Object **objects,
2180  uint objects_len,
2181  const float co[2],
2182  const bool extend,
2183  enum eUVLoopGenericType loop_type)
2184 {
2185  SpaceImage *sima = CTX_wm_space_image(C);
2186  const ARegion *region = CTX_wm_region(C);
2189  const ToolSettings *ts = scene->toolsettings;
2190  UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
2191  bool found_item = false;
2192  /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
2193  int flush = 0;
2194 
2195  /* Find edge. */
2196  found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
2197  if (!found_item) {
2198  return OPERATOR_CANCELLED;
2199  }
2200 
2201  Object *obedit = hit.ob;
2202  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2203 
2204  /* Do selection. */
2205  if (!extend) {
2206  uv_select_all_perform_multi_ex(scene, objects, objects_len, SEL_DESELECT, obedit);
2207  }
2208 
2209  if (loop_type == UV_LOOP_SELECT) {
2210  flush = uv_select_edgeloop(sima, scene, obedit, &hit, extend);
2211  }
2212  else if (loop_type == UV_RING_SELECT) {
2213  flush = uv_select_edgering(sima, scene, obedit, &hit, extend);
2214  }
2215  else {
2217  }
2218 
2219  if (ts->uv_flag & UV_SYNC_SELECTION) {
2220  if (flush == 1) {
2221  EDBM_select_flush(em);
2222  }
2223  else if (flush == -1) {
2224  EDBM_deselect_flush(em);
2225  }
2226  }
2227 
2228  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2229  Object *obiter = objects[ob_index];
2231  }
2232 
2234 }
2236  const float co[2],
2237  const bool extend,
2238  enum eUVLoopGenericType loop_type)
2239 {
2240  ViewLayer *view_layer = CTX_data_view_layer(C);
2241  uint objects_len = 0;
2243  view_layer, ((View3D *)NULL), &objects_len);
2244  int ret = uv_mouse_select_loop_generic_multi(C, objects, objects_len, co, extend, loop_type);
2245  MEM_freeN(objects);
2246  return ret;
2247 }
2248 
2251 /* -------------------------------------------------------------------- */
2256 {
2257  float co[2];
2258 
2259  RNA_float_get_array(op->ptr, "location", co);
2260  const bool extend = RNA_boolean_get(op->ptr, "extend");
2261 
2265  /* For now ring-select and face-loop is the same thing,
2266  * if we support real edge selection this will no longer be the case. */
2267  type = UV_RING_SELECT;
2268  }
2269 
2270  return uv_mouse_select_loop_generic(C, co, extend, type);
2271 }
2272 
2273 static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2274 {
2275  const ARegion *region = CTX_wm_region(C);
2276  float co[2];
2277 
2278  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2279  RNA_float_set_array(op->ptr, "location", co);
2280 
2281  return uv_select_loop_exec(C, op);
2282 }
2283 
2285 {
2286  /* identifiers */
2287  ot->name = "Loop Select";
2288  ot->description = "Select a loop of connected UV vertices";
2289  ot->idname = "UV_OT_select_loop";
2290  ot->flag = OPTYPE_UNDO;
2291 
2292  /* api callbacks */
2295  ot->poll = ED_operator_uvedit; /* requires space image */
2296 
2297  /* properties */
2299  "extend",
2300  0,
2301  "Extend",
2302  "Extend selection rather than clearing the existing selection");
2304  ot->srna,
2305  "location",
2306  2,
2307  NULL,
2308  -FLT_MAX,
2309  FLT_MAX,
2310  "Location",
2311  "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
2312  -100.0f,
2313  100.0f);
2314 }
2315 
2318 /* -------------------------------------------------------------------- */
2323 {
2324  float co[2];
2325  RNA_float_get_array(op->ptr, "location", co);
2326  const bool extend = RNA_boolean_get(op->ptr, "extend");
2327  return uv_mouse_select_loop_generic(C, co, extend, UV_RING_SELECT);
2328 }
2329 
2330 static int uv_select_edge_ring_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2331 {
2332  const ARegion *region = CTX_wm_region(C);
2333  float co[2];
2334 
2335  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2336  RNA_float_set_array(op->ptr, "location", co);
2337 
2338  return uv_select_edge_ring_exec(C, op);
2339 }
2340 
2342 {
2343  /* identifiers */
2344  ot->name = "Edge Ring Select";
2345  ot->description = "Select an edge ring of connected UV vertices";
2346  ot->idname = "UV_OT_select_edge_ring";
2347  ot->flag = OPTYPE_UNDO;
2348 
2349  /* api callbacks */
2352  ot->poll = ED_operator_uvedit; /* requires space image */
2353 
2354  /* properties */
2356  "extend",
2357  0,
2358  "Extend",
2359  "Extend selection rather than clearing the existing selection");
2361  ot->srna,
2362  "location",
2363  2,
2364  NULL,
2365  -FLT_MAX,
2366  FLT_MAX,
2367  "Location",
2368  "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
2369  -100.0f,
2370  100.0f);
2371 }
2372 
2375 /* -------------------------------------------------------------------- */
2379 static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
2380 {
2381  const ARegion *region = CTX_wm_region(C);
2383  const ToolSettings *ts = scene->toolsettings;
2384  ViewLayer *view_layer = CTX_data_view_layer(C);
2385  bool extend = true;
2386  bool deselect = false;
2387  bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
2388 
2389  UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
2390 
2391  if (pick) {
2392  extend = RNA_boolean_get(op->ptr, "extend");
2393  deselect = RNA_boolean_get(op->ptr, "deselect");
2394  }
2395 
2396  uint objects_len = 0;
2398  view_layer, ((View3D *)NULL), &objects_len);
2399 
2400  if (pick) {
2401  float co[2];
2402 
2403  if (event) {
2404  /* invoke */
2405  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2406  RNA_float_set_array(op->ptr, "location", co);
2407  }
2408  else {
2409  /* exec */
2410  RNA_float_get_array(op->ptr, "location", co);
2411  }
2412 
2413  if (!uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit)) {
2414  MEM_freeN(objects);
2415  return OPERATOR_CANCELLED;
2416  }
2417  }
2418 
2419  if (!extend && !deselect) {
2420  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
2421  }
2422 
2424  scene, objects, objects_len, pick ? &hit : NULL, extend, deselect, false, select_faces);
2425 
2426  /* weak!, but works */
2427  Object **objects_free = objects;
2428  if (pick) {
2429  objects = &hit.ob;
2430  objects_len = 1;
2431  }
2432 
2433  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2434  Object *obedit = objects[ob_index];
2437  }
2438 
2439  MEM_SAFE_FREE(objects_free);
2440 
2441  return OPERATOR_FINISHED;
2442 }
2443 
2445 {
2446  return uv_select_linked_internal(C, op, NULL, false);
2447 }
2448 
2450 {
2451  /* identifiers */
2452  ot->name = "Select Linked";
2453  ot->description = "Select all UV vertices linked to the active UV map";
2454  ot->idname = "UV_OT_select_linked";
2455 
2456  /* api callbacks */
2458  ot->poll = ED_operator_uvedit; /* requires space image */
2459 
2460  /* flags */
2462 }
2463 
2466 /* -------------------------------------------------------------------- */
2471 {
2472  return uv_select_linked_internal(C, op, event, true);
2473 }
2474 
2476 {
2477  return uv_select_linked_internal(C, op, NULL, true);
2478 }
2479 
2481 {
2482  /* identifiers */
2483  ot->name = "Select Linked Pick";
2484  ot->description = "Select all UV vertices linked under the mouse";
2485  ot->idname = "UV_OT_select_linked_pick";
2486 
2487  /* flags */
2489 
2490  /* api callbacks */
2493  ot->poll = ED_operator_uvedit; /* requires space image */
2494 
2495  /* properties */
2497  "extend",
2498  0,
2499  "Extend",
2500  "Extend selection rather than clearing the existing selection");
2502  "deselect",
2503  0,
2504  "Deselect",
2505  "Deselect linked UV vertices rather than selecting them");
2507  ot->srna,
2508  "location",
2509  2,
2510  NULL,
2511  -FLT_MAX,
2512  FLT_MAX,
2513  "Location",
2514  "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
2515  -100.0f,
2516  100.0f);
2517 }
2518 
2521 /* -------------------------------------------------------------------- */
2532 {
2535  ViewLayer *view_layer = CTX_data_view_layer(C);
2536  const ToolSettings *ts = scene->toolsettings;
2537 
2538  BMFace *efa;
2539  BMLoop *l;
2540  BMIter iter, liter;
2541  MLoopUV *luv;
2542 
2543  if (ts->uv_flag & UV_SYNC_SELECTION) {
2544  BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
2545  return OPERATOR_CANCELLED;
2546  }
2547 
2548  bool changed_multi = false;
2549 
2550  uint objects_len = 0;
2552  view_layer, ((View3D *)NULL), &objects_len);
2553 
2554  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2555  Object *obedit = objects[ob_index];
2556  BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
2557 
2558  bool changed = false;
2559 
2560  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
2561 
2562  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2563  bool is_sel = false;
2564  bool is_unsel = false;
2565 
2566  if (!uvedit_face_visible_test(scene, efa)) {
2567  continue;
2568  }
2569 
2570  /* are we all selected? */
2571  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2572  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2573 
2574  if (luv->flag & MLOOPUV_VERTSEL) {
2575  is_sel = true;
2576  }
2577  else {
2578  is_unsel = true;
2579  }
2580 
2581  /* we have mixed selection, bail out */
2582  if (is_sel && is_unsel) {
2583  break;
2584  }
2585  }
2586 
2587  if (is_sel && is_unsel) {
2588  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2589  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2590  luv->flag &= ~MLOOPUV_VERTSEL;
2591  }
2592 
2593  changed = true;
2594  }
2595  }
2596 
2597  if (changed) {
2598  changed_multi = true;
2601  }
2602  }
2603  MEM_freeN(objects);
2604 
2605  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2606 }
2607 
2609 {
2610  /* identifiers */
2611  ot->name = "Select Split";
2612  ot->description = "Select only entirely selected faces";
2613  ot->idname = "UV_OT_select_split";
2615 
2616  /* api callbacks */
2618  ot->poll = ED_operator_uvedit; /* requires space image */
2619 }
2620 
2622  const ToolSettings *ts,
2623  Object *obedit)
2624 {
2625  if (ts->uv_flag & UV_SYNC_SELECTION) {
2628  }
2629  else {
2630  Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
2632  /* Only for region redraw. */
2634  }
2635 }
2636 
2639 /* -------------------------------------------------------------------- */
2649  BMEditMesh *em,
2650  UvVertMap *vmap,
2651  const uint efa_index,
2652  BMLoop *l,
2653  const bool select,
2654  const int cd_loop_uv_offset)
2655 {
2656  UvMapVert *start_vlist = NULL, *vlist_iter;
2657  BMFace *efa_vlist;
2658 
2659  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
2660 
2661  vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
2662 
2663  while (vlist_iter) {
2664  if (vlist_iter->separate) {
2665  start_vlist = vlist_iter;
2666  }
2667 
2668  if (efa_index == vlist_iter->poly_index) {
2669  break;
2670  }
2671 
2672  vlist_iter = vlist_iter->next;
2673  }
2674 
2675  vlist_iter = start_vlist;
2676  while (vlist_iter) {
2677 
2678  if (vlist_iter != start_vlist && vlist_iter->separate) {
2679  break;
2680  }
2681 
2682  if (efa_index != vlist_iter->poly_index) {
2683  BMLoop *l_other;
2684  efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
2685  /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
2686 
2687  l_other = BM_iter_at_index(
2688  em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
2689 
2690  uvedit_uv_select_set(scene, em, l_other, select, false, cd_loop_uv_offset);
2691  }
2692  vlist_iter = vlist_iter->next;
2693  }
2694 }
2695 
2707  Scene *scene,
2708  Object *obedit,
2709  const bool select)
2710 {
2711  /* Selecting UV Faces with some modes requires us to change
2712  * the selection in other faces (depending on the sticky mode).
2713  *
2714  * This only needs to be done when the Mesh is not used for
2715  * selection (so for sticky modes, vertex or location based). */
2716 
2717  const ToolSettings *ts = scene->toolsettings;
2718  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2719  BMFace *efa;
2720  BMLoop *l;
2721  BMIter iter, liter;
2722  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2723 
2724  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
2725  /* Tag all verts as untouched, then touch the ones that have a face center
2726  * in the loop and select all MLoopUV's that use a touched vert. */
2728 
2729  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2730  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2731  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2733  }
2734  }
2735  }
2736 
2737  /* now select tagged verts */
2738  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2739  /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
2740 
2741  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2742  if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
2743  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
2744  }
2745  }
2746  }
2747  }
2748  else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
2749  struct UvVertMap *vmap;
2750  uint efa_index;
2751 
2753  vmap = BM_uv_vert_map_create(em->bm, false, false);
2754  if (vmap == NULL) {
2755  return;
2756  }
2757 
2758  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
2759  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2760  /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
2761 
2762  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2764  scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
2765  }
2766  }
2767  }
2768  BM_uv_vert_map_free(vmap);
2769  }
2770  else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
2771  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2772  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2773  uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
2774  }
2775  }
2776  }
2777 }
2778 
2790  Scene *scene,
2791  Object *obedit,
2792  const bool select)
2793 {
2794  /* Selecting UV Loops with some modes requires us to change
2795  * the selection in other faces (depending on the sticky mode).
2796  *
2797  * This only needs to be done when the Mesh is not used for
2798  * selection (so for sticky modes, vertex or location based). */
2799 
2800  const ToolSettings *ts = scene->toolsettings;
2801  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2802  BMFace *efa;
2803  BMLoop *l;
2804  BMIter iter, liter;
2805 
2806  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2807 
2808  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
2809  /* Tag all verts as untouched, then touch the ones that have a face center
2810  * in the loop and select all MLoopUV's that use a touched vert. */
2812 
2813  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2814  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2817  }
2818  }
2819  }
2820 
2821  /* now select tagged verts */
2822  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2823  /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
2824 
2825  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2826  if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
2827  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
2828  }
2829  }
2830  }
2831  }
2832  else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
2833  struct UvVertMap *vmap;
2834  uint efa_index;
2835 
2837  vmap = BM_uv_vert_map_create(em->bm, false, false);
2838  if (vmap == NULL) {
2839  return;
2840  }
2841 
2842  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
2843  /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
2844 
2845  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2848  scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
2849  }
2850  }
2851  }
2852  BM_uv_vert_map_free(vmap);
2853  }
2854  else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
2855  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2856  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2858  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
2859  }
2860  }
2861  }
2862  }
2863 }
2864 
2867 /* -------------------------------------------------------------------- */
2872 {
2874  SpaceImage *sima = CTX_wm_space_image(C);
2876  const ToolSettings *ts = scene->toolsettings;
2877  ViewLayer *view_layer = CTX_data_view_layer(C);
2878  const ARegion *region = CTX_wm_region(C);
2879  BMFace *efa;
2880  BMLoop *l;
2881  BMIter iter, liter;
2882  MLoopUV *luv;
2883  rctf rectf;
2884  bool pinned;
2885  const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
2886  (ts->selectmode == SCE_SELECT_FACE) :
2887  (ts->uv_selectmode == UV_SELECT_FACE));
2888  const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
2889  (ts->selectmode == SCE_SELECT_EDGE) :
2890  (ts->uv_selectmode == UV_SELECT_EDGE));
2891  const bool use_select_linked = !(ts->uv_flag & UV_SYNC_SELECTION) &&
2893 
2894  /* get rectangle from operator */
2896  UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
2897 
2898  const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
2899  const bool select = (sel_op != SEL_OP_SUB);
2900  const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
2901 
2902  pinned = RNA_boolean_get(op->ptr, "pinned");
2903 
2904  bool changed_multi = false;
2905 
2906  uint objects_len = 0;
2908  view_layer, ((View3D *)NULL), &objects_len);
2909 
2910  if (use_pre_deselect) {
2911  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
2912  }
2913 
2914  /* don't indent to avoid diff noise! */
2915  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2916  Object *obedit = objects[ob_index];
2917  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2918 
2919  bool changed = false;
2920 
2921  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2922 
2923  /* do actual selection */
2924  if (use_face_center && !pinned) {
2925  /* handle face selection mode */
2926  float cent[2];
2927 
2928  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2929  /* assume not touched */
2931 
2932  if (uvedit_face_visible_test(scene, efa)) {
2933  BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
2934  if (BLI_rctf_isect_pt_v(&rectf, cent)) {
2936  changed = true;
2937  }
2938  }
2939  }
2940 
2941  /* (de)selects all tagged faces and deals with sticky modes */
2942  if (changed) {
2943  uv_select_flush_from_tag_face(sima, scene, obedit, select);
2944  }
2945  }
2946  else if (use_edge && !pinned) {
2947  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2948  if (!uvedit_face_visible_test(scene, efa)) {
2949  continue;
2950  }
2951 
2952  BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
2953  MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
2954 
2955  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2956  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2957  if (BLI_rctf_isect_pt_v(&rectf, luv->uv) && BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) {
2959  sima, scene, em, l_prev, select, false, cd_loop_uv_offset);
2960  changed = true;
2961  }
2962  l_prev = l;
2963  luv_prev = luv;
2964  }
2965  }
2966  }
2967  else {
2968  /* other selection modes */
2969  changed = true;
2971 
2972  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2973  if (!uvedit_face_visible_test(scene, efa)) {
2974  continue;
2975  }
2976  bool has_selected = false;
2977  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2978  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2979  if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
2980  if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
2981  /* UV_SYNC_SELECTION - can't do pinned selection */
2982  if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
2983  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
2985  has_selected = true;
2986  }
2987  }
2988  else if (pinned) {
2989  if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
2990  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
2992  }
2993  }
2994  }
2995  }
2996  if (has_selected && use_select_linked) {
2997  UvNearestHit hit = {
2998  .ob = obedit,
2999  .efa = efa,
3000  };
3001  uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false);
3002  }
3003  }
3004 
3005  if (sima->sticky == SI_STICKY_VERTEX) {
3006  uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
3007  }
3008  }
3009 
3010  if (changed || use_pre_deselect) {
3011  changed_multi = true;
3012 
3015  }
3016  }
3017 
3018  MEM_freeN(objects);
3019 
3020  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3021 }
3022 
3024 {
3025  /* identifiers */
3026  ot->name = "Box Select";
3027  ot->description = "Select UV vertices using box selection";
3028  ot->idname = "UV_OT_select_box";
3029 
3030  /* api callbacks */
3034  ot->poll = ED_operator_uvedit_space_image; /* requires space image */
3036 
3037  /* flags */
3038  ot->flag = OPTYPE_UNDO;
3039 
3040  /* properties */
3041  RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
3042 
3045 }
3046 
3049 /* -------------------------------------------------------------------- */
3053 static int uv_circle_select_is_point_inside(const float uv[2],
3054  const float offset[2],
3055  const float ellipse[2])
3056 {
3057  /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
3058  const float co[2] = {
3059  (uv[0] - offset[0]) * ellipse[0],
3060  (uv[1] - offset[1]) * ellipse[1],
3061  };
3062  return len_squared_v2(co) < 1.0f;
3063 }
3064 
3065 static int uv_circle_select_is_edge_inside(const float uv_a[2],
3066  const float uv_b[2],
3067  const float offset[2],
3068  const float ellipse[2])
3069 {
3070  /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
3071  const float co_a[2] = {
3072  (uv_a[0] - offset[0]) * ellipse[0],
3073  (uv_a[1] - offset[1]) * ellipse[1],
3074  };
3075  const float co_b[2] = {
3076  (uv_b[0] - offset[0]) * ellipse[0],
3077  (uv_b[1] - offset[1]) * ellipse[1],
3078  };
3079  return dist_squared_to_line_segment_v2((const float[2]){0.0f, 0.0f}, co_a, co_b) < 1.0f;
3080 }
3081 
3083 {
3085  SpaceImage *sima = CTX_wm_space_image(C);
3087  ViewLayer *view_layer = CTX_data_view_layer(C);
3088  const ToolSettings *ts = scene->toolsettings;
3089  const ARegion *region = CTX_wm_region(C);
3090  BMFace *efa;
3091  BMLoop *l;
3092  BMIter iter, liter;
3093  MLoopUV *luv;
3094  int x, y, radius, width, height;
3095  float zoomx, zoomy;
3096  float offset[2], ellipse[2];
3097 
3098  const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3099  (ts->selectmode == SCE_SELECT_FACE) :
3100  (ts->uv_selectmode == UV_SELECT_FACE));
3101  const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3102  (ts->selectmode == SCE_SELECT_EDGE) :
3103  (ts->uv_selectmode == UV_SELECT_EDGE));
3104  const bool use_select_linked = !(ts->uv_flag & UV_SYNC_SELECTION) &&
3106 
3107  /* get operator properties */
3108  x = RNA_int_get(op->ptr, "x");
3109  y = RNA_int_get(op->ptr, "y");
3110  radius = RNA_int_get(op->ptr, "radius");
3111 
3112  /* compute ellipse size and location, not a circle since we deal
3113  * with non square image. ellipse is normalized, r = 1.0. */
3115  ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
3116 
3117  ellipse[0] = width * zoomx / radius;
3118  ellipse[1] = height * zoomy / radius;
3119 
3120  UI_view2d_region_to_view(&region->v2d, x, y, &offset[0], &offset[1]);
3121 
3122  bool changed_multi = false;
3123 
3124  uint objects_len = 0;
3126  view_layer, ((View3D *)NULL), &objects_len);
3127 
3128  const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
3130  const bool select = (sel_op != SEL_OP_SUB);
3131  const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
3132 
3133  if (use_pre_deselect) {
3134  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
3135  }
3136 
3137  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3138  Object *obedit = objects[ob_index];
3139  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3140 
3141  bool changed = false;
3142 
3143  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3144 
3145  /* do selection */
3146  if (use_face_center) {
3147  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3149  /* assume not touched */
3150  if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
3151  float cent[2];
3152  BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
3153  if (uv_circle_select_is_point_inside(cent, offset, ellipse)) {
3155  changed = true;
3156  }
3157  }
3158  }
3159 
3160  /* (de)selects all tagged faces and deals with sticky modes */
3161  if (changed) {
3162  uv_select_flush_from_tag_face(sima, scene, obedit, select);
3163  }
3164  }
3165  else if (use_edge) {
3166  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3167  if (!uvedit_face_visible_test(scene, efa)) {
3168  continue;
3169  }
3170 
3171  BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
3172  MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
3173 
3174  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3175  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3176  if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) {
3178  sima, scene, em, l_prev, select, false, cd_loop_uv_offset);
3179  changed = true;
3180  }
3181  l_prev = l;
3182  luv_prev = luv;
3183  }
3184  }
3185  }
3186  else {
3188 
3189  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3190  if (!uvedit_face_visible_test(scene, efa)) {
3191  continue;
3192  }
3193  bool has_selected = false;
3194  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3195  if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
3196  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3197  if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) {
3198  changed = true;
3199  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
3201  has_selected = true;
3202  }
3203  }
3204  }
3205  if (has_selected && use_select_linked) {
3206  UvNearestHit hit = {
3207  .ob = obedit,
3208  .efa = efa,
3209  };
3210  uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false);
3211  }
3212  }
3213 
3214  if (sima->sticky == SI_STICKY_VERTEX) {
3215  uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
3216  }
3217  }
3218 
3219  if (changed || use_pre_deselect) {
3220  changed_multi = true;
3221 
3224  }
3225  }
3226  MEM_freeN(objects);
3227 
3228  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3229 }
3230 
3232 {
3233  /* identifiers */
3234  ot->name = "Circle Select";
3235  ot->description = "Select UV vertices using circle selection";
3236  ot->idname = "UV_OT_select_circle";
3237 
3238  /* api callbacks */
3242  ot->poll = ED_operator_uvedit_space_image; /* requires space image */
3244 
3245  /* flags */
3246  ot->flag = OPTYPE_UNDO;
3247 
3248  /* properties */
3251 }
3252 
3255 /* -------------------------------------------------------------------- */
3260  const rcti *clip_rect,
3261  const int mcoords[][2],
3262  const int mcoords_len,
3263  const float co_test[2])
3264 {
3265  int co_screen[2];
3267  &region->v2d, co_test[0], co_test[1], &co_screen[0], &co_screen[1]) &&
3268  BLI_rcti_isect_pt_v(clip_rect, co_screen) &&
3270  mcoords, mcoords_len, co_screen[0], co_screen[1], V2D_IS_CLIPPED)) {
3271  return true;
3272  }
3273  return false;
3274 }
3275 
3277  const int mcoords[][2],
3278  const int mcoords_len,
3279  const eSelectOp sel_op)
3280 {
3282  SpaceImage *sima = CTX_wm_space_image(C);
3283  const ARegion *region = CTX_wm_region(C);
3285  const ToolSettings *ts = scene->toolsettings;
3286  ViewLayer *view_layer = CTX_data_view_layer(C);
3287  const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3288  (ts->selectmode == SCE_SELECT_FACE) :
3289  (ts->uv_selectmode == UV_SELECT_FACE));
3290  const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3291  (ts->selectmode == SCE_SELECT_EDGE) :
3292  (ts->uv_selectmode == UV_SELECT_EDGE));
3293  const bool use_select_linked = !(ts->uv_flag & UV_SYNC_SELECTION) &&
3295 
3296  const bool select = (sel_op != SEL_OP_SUB);
3297  const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
3298 
3299  BMIter iter, liter;
3300 
3301  BMFace *efa;
3302  BMLoop *l;
3303  bool changed_multi = false;
3304  rcti rect;
3305 
3306  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
3307 
3308  uint objects_len = 0;
3310  view_layer, ((View3D *)NULL), &objects_len);
3311 
3312  if (use_pre_deselect) {
3313  uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
3314  }
3315 
3316  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3317  Object *obedit = objects[ob_index];
3318 
3319  bool changed = false;
3320 
3321  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3322 
3323  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3324 
3325  if (use_face_center) { /* Face Center Select. */
3326  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3328  /* assume not touched */
3329  if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
3330  float cent[2];
3331  BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
3332  if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) {
3334  changed = true;
3335  }
3336  }
3337  }
3338 
3339  /* (de)selects all tagged faces and deals with sticky modes */
3340  if (changed) {
3341  uv_select_flush_from_tag_face(sima, scene, obedit, select);
3342  }
3343  }
3344  else if (use_edge) {
3345  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3346  if (!uvedit_face_visible_test(scene, efa)) {
3347  continue;
3348  }
3349 
3350  BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
3351  MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
3352 
3353  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3354  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3356  region, &rect, mcoords, mcoords_len, luv->uv) &&
3358  region, &rect, mcoords, mcoords_len, luv_prev->uv)) {
3360  sima, scene, em, l_prev, select, false, cd_loop_uv_offset);
3361  changed = true;
3362  }
3363  l_prev = l;
3364  luv_prev = luv;
3365  }
3366  }
3367  }
3368  else { /* Vert Selection. */
3370 
3371  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3372  if (!uvedit_face_visible_test(scene, efa)) {
3373  continue;
3374  }
3375  bool has_selected = false;
3376  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3377  if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
3378  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3380  region, &rect, mcoords, mcoords_len, luv->uv)) {
3381  uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
3382  changed = true;
3384  has_selected = true;
3385  }
3386  }
3387  }
3388  if (has_selected && use_select_linked) {
3389  UvNearestHit hit = {
3390  .ob = obedit,
3391  .efa = efa,
3392  };
3393  uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false);
3394  }
3395  }
3396 
3397  if (sima->sticky == SI_STICKY_VERTEX) {
3398  uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
3399  }
3400  }
3401 
3402  if (changed || use_pre_deselect) {
3403  changed_multi = true;
3404 
3407  }
3408  }
3409  MEM_freeN(objects);
3410 
3411  return changed_multi;
3412 }
3413 
3415 {
3416  int mcoords_len;
3417  const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
3418 
3419  if (mcoords) {
3420  const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
3421  bool changed = do_lasso_select_mesh_uv(C, mcoords, mcoords_len, sel_op);
3422  MEM_freeN((void *)mcoords);
3423 
3424  return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3425  }
3426 
3427  return OPERATOR_PASS_THROUGH;
3428 }
3429 
3431 {
3432  ot->name = "Lasso Select UV";
3433  ot->description = "Select UVs using lasso selection";
3434  ot->idname = "UV_OT_select_lasso";
3435 
3441 
3442  /* flags */
3443  ot->flag = OPTYPE_UNDO;
3444 
3445  /* properties */
3448 }
3449 
3452 /* -------------------------------------------------------------------- */
3457 {
3460  const ToolSettings *ts = scene->toolsettings;
3461  ViewLayer *view_layer = CTX_data_view_layer(C);
3462  BMFace *efa;
3463  BMLoop *l;
3464  BMIter iter, liter;
3465  MLoopUV *luv;
3466 
3467  uint objects_len = 0;
3469  view_layer, ((View3D *)NULL), &objects_len);
3470 
3471  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3472  Object *obedit = objects[ob_index];
3473  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3474 
3475  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3476  bool changed = false;
3477 
3478  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3479  if (!uvedit_face_visible_test(scene, efa)) {
3480  continue;
3481  }
3482 
3483  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3484  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3485 
3486  if (luv->flag & MLOOPUV_PINNED) {
3487  uvedit_uv_select_enable(scene, em, l, false, cd_loop_uv_offset);
3488  changed = true;
3489  }
3490  }
3491  }
3492 
3493  if (changed) {
3495  }
3496  }
3497  MEM_freeN(objects);
3498 
3499  return OPERATOR_FINISHED;
3500 }
3501 
3503 {
3504  /* identifiers */
3505  ot->name = "Selected Pinned";
3506  ot->description = "Select all pinned UV vertices";
3507  ot->idname = "UV_OT_select_pinned";
3509 
3510  /* api callbacks */
3513 }
3514 
3517 /* -------------------------------------------------------------------- */
3521 BLI_INLINE uint overlap_hash(const void *overlap_v)
3522 {
3523  const BVHTreeOverlap *overlap = overlap_v;
3524 
3525  /* Designed to treat (A,B) and (B,A) as the same. */
3526  int x = overlap->indexA;
3527  int y = overlap->indexB;
3528  if (x > y) {
3529  SWAP(int, x, y);
3530  }
3531  return BLI_hash_int_2d(x, y);
3532 }
3533 
3534 BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
3535 {
3536  const BVHTreeOverlap *a = a_v;
3537  const BVHTreeOverlap *b = b_v;
3538  return !((a->indexA == b->indexA && a->indexB == b->indexB) ||
3539  (a->indexA == b->indexB && a->indexB == b->indexA));
3540 }
3541 
3545  float tri[3][2];
3546 };
3547 
3555 static bool overlap_tri_tri_uv_test(const float t1[3][2],
3556  const float t2[3][2],
3557  const float endpoint_bias)
3558 {
3559  float vi[2];
3560 
3561  /* Don't use 'isect_tri_tri_v2' here
3562  * because it's important to ignore overlap at end-points. */
3563  if (isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 ||
3564  isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 ||
3565  isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 ||
3566  isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 ||
3567  isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 ||
3568  isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 ||
3569  isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 ||
3570  isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1) {
3571  return true;
3572  }
3573 
3574  /* When none of the segments intersect, checking if either of the triangles corners
3575  * is inside the others is almost always sufficient to test if the two triangles intersect.
3576  *
3577  * However, the `endpoint_bias` on segment intersections causes _exact_ overlapping
3578  * triangles not to be detected.
3579  *
3580  * Resolve this problem at the small cost of calculating the triangle center, see T85508. */
3581  mid_v2_v2v2v2(vi, UNPACK3(t1));
3582  if (isect_point_tri_v2(vi, UNPACK3(t2)) != 0) {
3583  return true;
3584  }
3585  mid_v2_v2v2v2(vi, UNPACK3(t2));
3586  if (isect_point_tri_v2(vi, UNPACK3(t1)) != 0) {
3587  return true;
3588  }
3589 
3590  return false;
3591 }
3592 
3593 static int uv_select_overlap(bContext *C, const bool extend)
3594 {
3597  ViewLayer *view_layer = CTX_data_view_layer(C);
3598 
3599  uint objects_len = 0;
3601  view_layer, ((View3D *)NULL), &objects_len);
3602 
3603  /* Calculate maximum number of tree nodes and prepare initial selection. */
3604  uint uv_tri_len = 0;
3605  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3606  Object *obedit = objects[ob_index];
3607  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3608 
3612  if (!extend) {
3614  }
3615 
3616  BMIter iter;
3617  BMFace *efa;
3618  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3620  continue;
3621  }
3622  uv_tri_len += efa->len - 2;
3623  }
3624  }
3625 
3626  struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len,
3627  "UvOverlapData");
3628  BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6);
3629 
3630  /* Use a global data index when inserting into the BVH. */
3631  int data_index = 0;
3632 
3633  int face_len_alloc = 3;
3634  float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords");
3635  uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris");
3636 
3637  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3638  Object *obedit = objects[ob_index];
3639  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3640  BMIter iter, liter;
3641  BMFace *efa;
3642  BMLoop *l;
3643 
3644  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3645 
3646  /* Triangulate each UV face and store it inside the BVH. */
3647  int face_index;
3648  BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
3649 
3651  continue;
3652  }
3653 
3654  const uint face_len = efa->len;
3655  const uint tri_len = face_len - 2;
3656 
3657  if (face_len_alloc < face_len) {
3658  MEM_freeN(uv_verts);
3659  MEM_freeN(indices);
3660  uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords");
3661  indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris");
3662  face_len_alloc = face_len;
3663  }
3664 
3665  int vert_index;
3666  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) {
3667  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3668  copy_v2_v2(uv_verts[vert_index], luv->uv);
3669  }
3670 
3671  BLI_polyfill_calc(uv_verts, face_len, 0, indices);
3672 
3673  for (int t = 0; t < tri_len; t++) {
3674  overlap_data[data_index].ob_index = ob_index;
3675  overlap_data[data_index].face_index = face_index;
3676 
3677  /* BVH needs 3D, overlap data uses 2D. */
3678  const float tri[3][3] = {
3679  {UNPACK2(uv_verts[indices[t][0]]), 0.0f},
3680  {UNPACK2(uv_verts[indices[t][1]]), 0.0f},
3681  {UNPACK2(uv_verts[indices[t][2]]), 0.0f},
3682  };
3683 
3684  copy_v2_v2(overlap_data[data_index].tri[0], tri[0]);
3685  copy_v2_v2(overlap_data[data_index].tri[1], tri[1]);
3686  copy_v2_v2(overlap_data[data_index].tri[2], tri[2]);
3687 
3688  BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3);
3689  data_index++;
3690  }
3691  }
3692  }
3693  BLI_assert(data_index == uv_tri_len);
3694 
3695  MEM_freeN(uv_verts);
3696  MEM_freeN(indices);
3697 
3698  BLI_bvhtree_balance(uv_tree);
3699 
3700  uint tree_overlap_len;
3701  BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL);
3702 
3703  if (overlap != NULL) {
3704  GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len);
3705 
3706  for (int i = 0; i < tree_overlap_len; i++) {
3707  /* Skip overlaps against yourself. */
3708  if (overlap[i].indexA == overlap[i].indexB) {
3709  continue;
3710  }
3711 
3712  /* Skip overlaps that have already been tested. */
3713  if (!BLI_gset_add(overlap_set, &overlap[i])) {
3714  continue;
3715  }
3716 
3717  const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA];
3718  const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB];
3719  Object *obedit_a = objects[o_a->ob_index];
3720  Object *obedit_b = objects[o_b->ob_index];
3721  BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a);
3722  BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b);
3723  BMFace *face_a = em_a->bm->ftable[o_a->face_index];
3724  BMFace *face_b = em_b->bm->ftable[o_b->face_index];
3725  const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV);
3726  const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV);
3727 
3728  /* Skip if both faces are already selected. */
3729  if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) &&
3730  uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) {
3731  continue;
3732  }
3733 
3734  /* Main tri-tri overlap test. */
3735  const float endpoint_bias = -1e-4f;
3736  if (overlap_tri_tri_uv_test(o_a->tri, o_b->tri, endpoint_bias)) {
3737  uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a);
3738  uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b);
3739  }
3740  }
3741 
3742  BLI_gset_free(overlap_set, NULL);
3743  MEM_freeN(overlap);
3744  }
3745 
3746  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3748  }
3749 
3750  BLI_bvhtree_free(uv_tree);
3751 
3752  MEM_freeN(overlap_data);
3753  MEM_freeN(objects);
3754 
3755  return OPERATOR_FINISHED;
3756 }
3757 
3759 {
3760  bool extend = RNA_boolean_get(op->ptr, "extend");
3761  return uv_select_overlap(C, extend);
3762 }
3763 
3765 {
3766  /* identifiers */
3767  ot->name = "Select Overlap";
3768  ot->description = "Select all UV faces which overlap each other";
3769  ot->idname = "UV_OT_select_overlap";
3771 
3772  /* api callbacks */
3775 
3776  /* properties */
3778  "extend",
3779  0,
3780  "Extend",
3781  "Extend selection rather than clearing the existing selection");
3782 }
3783 
3786 /* -------------------------------------------------------------------- */
3793 BMFace **ED_uvedit_selected_faces(Scene *scene, BMesh *bm, int len_max, int *r_faces_len)
3794 {
3795  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
3796  CLAMP_MAX(len_max, bm->totface);
3797  int faces_len = 0;
3798  BMFace **faces = MEM_mallocN(sizeof(*faces) * len_max, __func__);
3799 
3800  BMIter iter;
3801  BMFace *f;
3802  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3803  if (uvedit_face_visible_test(scene, f)) {
3804  if (uvedit_face_select_test(scene, f, cd_loop_uv_offset)) {
3805  faces[faces_len++] = f;
3806  if (faces_len == len_max) {
3807  goto finally;
3808  }
3809  }
3810  }
3811  }
3812 
3813 finally:
3814  *r_faces_len = faces_len;
3815  if (faces_len != len_max) {
3816  faces = MEM_reallocN(faces, sizeof(*faces) * faces_len);
3817  }
3818  return faces;
3819 }
3820 
3821 BMLoop **ED_uvedit_selected_edges(Scene *scene, BMesh *bm, int len_max, int *r_edges_len)
3822 {
3823  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
3824  CLAMP_MAX(len_max, bm->totloop);
3825  int edges_len = 0;
3826  BMLoop **edges = MEM_mallocN(sizeof(*edges) * len_max, __func__);
3827 
3828  BMIter iter;
3829  BMFace *f;
3830 
3831  /* Clear tag. */
3832  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3833  BMIter liter;
3834  BMLoop *l_iter;
3835  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
3837  }
3838  }
3839 
3840  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3841  if (uvedit_face_visible_test(scene, f)) {
3842  BMIter liter;
3843  BMLoop *l_iter;
3844  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
3845  if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
3846  const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
3847  const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l_iter->next, cd_loop_uv_offset);
3848  if ((luv_curr->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL)) {
3850 
3851  edges[edges_len++] = l_iter;
3852  if (edges_len == len_max) {
3853  goto finally;
3854  }
3855 
3856  /* Tag other connected loops so we don't consider them separate edges. */
3857  if (l_iter != l_iter->radial_next) {
3858  BMLoop *l_radial_iter = l_iter->radial_next;
3859  do {
3860  if (BM_loop_uv_share_edge_check(l_iter, l_radial_iter, cd_loop_uv_offset)) {
3861  BM_elem_flag_enable(l_radial_iter, BM_ELEM_TAG);
3862  }
3863  } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
3864  }
3865  }
3866  }
3867  }
3868  }
3869  }
3870 
3871 finally:
3872  *r_edges_len = edges_len;
3873  if (edges_len != len_max) {
3874  edges = MEM_reallocN(edges, sizeof(*edges) * edges_len);
3875  }
3876  return edges;
3877 }
3878 
3879 BMLoop **ED_uvedit_selected_verts(Scene *scene, BMesh *bm, int len_max, int *r_verts_len)
3880 {
3881  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
3882  CLAMP_MAX(len_max, bm->totloop);
3883  int verts_len = 0;
3884  BMLoop **verts = MEM_mallocN(sizeof(*verts) * len_max, __func__);
3885 
3886  BMIter iter;
3887  BMFace *f;
3888 
3889  /* Clear tag. */
3890  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3891  BMIter liter;
3892  BMLoop *l_iter;
3893  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
3895  }
3896  }
3897 
3898  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3899  if (uvedit_face_visible_test(scene, f)) {
3900  BMIter liter;
3901  BMLoop *l_iter;
3902  BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
3903  if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
3904  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
3905  if ((luv->flag & MLOOPUV_VERTSEL)) {
3906  BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
3907 
3908  verts[verts_len++] = l_iter;
3909  if (verts_len == len_max) {
3910  goto finally;
3911  }
3912 
3913  /* Tag other connected loops so we don't consider them separate vertices. */
3914  BMIter liter_disk;
3915  BMLoop *l_disk_iter;
3916  BM_ITER_ELEM (l_disk_iter, &liter_disk, l_iter->v, BM_LOOPS_OF_VERT) {
3917  if (BM_loop_uv_share_vert_check(l_iter, l_disk_iter, cd_loop_uv_offset)) {
3918  BM_elem_flag_enable(l_disk_iter, BM_ELEM_TAG);
3919  }
3920  }
3921  }
3922  }
3923  }
3924  }
3925  }
3926 
3927 finally:
3928  *r_verts_len = verts_len;
3929  if (verts_len != len_max) {
3930  verts = MEM_reallocN(verts, sizeof(*verts) * verts_len);
3931  }
3932  return verts;
3933 }
3934 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:800
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const struct CustomData *data, int type)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:434
void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode)
Definition: mesh_runtime.c:251
@ BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_assert_unreachable()
Definition: BLI_assert.h:96
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
struct GSet GSet
Definition: BLI_ghash.h:189
GSet * BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1117
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:1160
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
Definition: BLI_hash.h:67
BVHTreeOverlap * BLI_bvhtree_overlap(const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_tot, BVHTree_OverlapCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1401
void BLI_bvhtree_balance(BVHTree *tree)
Definition: BLI_kdopbvh.c:956
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
Definition: BLI_kdopbvh.c:873
void BLI_bvhtree_free(BVHTree *tree)
Definition: BLI_kdopbvh.c:945
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
Definition: BLI_kdopbvh.c:998
void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], const unsigned int mcoords_len)
Definition: lasso_2d.c:31
bool BLI_lasso_is_point_inside(const int mcoords[][2], const unsigned int mcoords_len, const int sx, const int sy, const int error_value)
Definition: lasso_2d.c:54
MINLINE float square_f(float a)
void 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:353
int isect_seg_seg_v2_point_ex(const float v0[2], const float v1[2], const float v2[2], const float v3[2], const float endpoint_bias, float vi[2])
Definition: math_geom.c:1252
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:1595
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:338
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
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:283
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) ATTR_WARN_UNUSED_RESULT
void BLI_polyfill_calc(const float(*coords)[2], const unsigned int coords_tot, const int coords_sign, unsigned int(*r_tris)[3])
Definition: polyfill_2d.c:905
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])
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNPACK2(a)
#define CLAMP_MAX(a, c)
#define ARRAY_SIZE(arr)
#define SWAP(type, a, b)
#define UNUSED(x)
#define UNPACK3(a)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
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:654
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
@ CD_MLOOPUV
@ MLOOPUV_PINNED
@ MLOOPUV_VERTSEL
Object is a sort of wrapper for general info.
#define UV_SELECT_EDGE
#define UV_SELECT_FACE
#define SCE_SELECT_FACE
#define UV_SYNC_SELECTION
#define SCE_SELECT_VERTEX
#define UV_SELECT_ISLAND
#define UV_SELECT_VERTEX
#define SCE_SELECT_EDGE
@ SI_STICKY_VERTEX
@ SI_STICKY_LOC
@ SI_STICKY_DISABLE
@ 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:215
void EDBM_select_more(struct BMEditMesh *em, const bool use_face_step)
struct UvMapVert * BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v)
void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag)
void EDBM_select_flush(struct BMEditMesh *em)
void EDBM_select_less(struct BMEditMesh *em, const bool use_face_step)
struct UvVertMap * BM_uv_vert_map_create(struct BMesh *bm, const bool use_select, const bool use_winding)
void EDBM_select_toggle_all(struct BMEditMesh *em)
void EDBM_deselect_flush(struct BMEditMesh *em)
void EDBM_select_swap(struct BMEditMesh *em)
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag)
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:518
bool ED_operator_uvedit(struct bContext *C)
Definition: screen_ops.c:511
#define SEL_OP_USE_PRE_DESELECT(sel_op)
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first)
Definition: select_utils.c:77
eSelectOp
@ SEL_OP_SUB
_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 type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei 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:204
#define C
Definition: RandGen.cpp:39
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:40
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_SPACE_IMAGE
Definition: WM_types.h:417
#define ND_SELECT
Definition: WM_types.h:407
#define NC_SPACE
Definition: WM_types.h:293
#define BM_DISK_EDGE_NEXT(e, v)
Definition: bmesh_class.h:556
@ 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_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:27
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
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_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ 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.c:2276
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:110
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1426
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
Definition: bmesh_query.c:1403
BLI_INLINE 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 ushort indices[]
static float verts[][3]
#define sqrtf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static char faces[256]
static unsigned a[3]
Definition: RandGen.cpp:92
return ret
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:6390
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3851
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMLoop * l
Definition: bmesh_class.h:140
struct BMesh * bm
Definition: BKE_editmesh.h:52
struct BMEditSelection * prev
Definition: bmesh_marking.h:24
int len
Definition: bmesh_class.h:279
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
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:47
void * data
struct ToolSettings * toolsettings
float tri[3][2]
struct UvMapVert * next
unsigned int poly_index
struct BMLoop * l
Definition: uvedit_intern.h:43
struct Object * ob
Definition: uvedit_intern.h:40
float scale[2]
Definition: uvedit_intern.h:53
struct BMFace * efa
Definition: uvedit_intern.h:42
int mval[2]
Definition: WM_types.h:583
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
struct PointerRNA * ptr
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
#define UV_NEAREST_HIT_INIT_MAX(v2d)
Definition: uvedit_intern.h:65
#define UV_NEAREST_HIT_INIT_DIST_PX(v2d, dist_px)
Definition: uvedit_intern.h:56
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)
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])
static void uv_select_all_perform_multi_ex(Scene *scene, Object **objects, const uint objects_len, int action, const Object *ob_exclude)
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)
#define SET_SELECTION(value)
bool uv_find_nearest_face_multi(Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit)
bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
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 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])
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 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)
void UV_OT_select_linked(wmOperatorType *ot)
static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
static int uv_mouse_select(bContext *C, const float co[2], const bool extend, const bool deselect_all)
BMLoop * uv_find_nearest_loop_from_edge(struct Scene *scene, struct Object *obedit, struct BMEdge *e, const float co[2])
bool ED_uvedit_nearest_uv(const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2])
BMLoop ** ED_uvedit_selected_verts(Scene *scene, BMesh *bm, int len_max, int *r_verts_len)
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_circle_select_is_point_inside(const float uv[2], const float offset[2], const float ellipse[2])
bool uvedit_select_is_any_selected_multi(Scene *scene, Object **objects, const uint objects_len)
BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
static int uv_box_select_exec(bContext *C, wmOperator *op)
char ED_uvedit_select_mode_get(const Scene *scene)
static int uv_mouse_select_multi(bContext *C, Object **objects, uint objects_len, const float co[2], const bool extend, const bool deselect_all)
static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool uvedit_select_is_any_selected(Scene *scene, Object *obedit)
static int uv_select_edgering(const SpaceImage *sima, Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
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)
bool ED_uvedit_nearest_uv_multi(const Scene *scene, Object **objects, const uint objects_len, const float co[2], float *dist_sq, float r_uv[2])
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)
bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa)
void UV_OT_select_linked_pick(wmOperatorType *ot)
void UV_OT_select_more(wmOperatorType *ot)
void UV_OT_select_pinned(wmOperatorType *ot)
static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select)
void UV_OT_select_loop(wmOperatorType *ot)
void uvedit_face_select_set(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, const bool do_history, const int cd_loop_uv_offset)
BLI_INLINE uint overlap_hash(const void *overlap_v)
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)
BMLoop ** ED_uvedit_selected_edges(Scene *scene, BMesh *bm, int len_max, int *r_edges_len)
void uvedit_edge_select_set_with_sticky(const struct SpaceImage *sima, const Scene *scene, BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, const uint cd_loop_uv_offset)
bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
BMLoop * ED_uvedit_active_edge_loop_get(BMesh *bm)
eUVLoopGenericType
@ UV_RING_SELECT
@ UV_LOOP_SELECT
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])
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)
static int uv_select_more_less(bContext *C, const bool select)
static void uv_select_all_perform_multi(Scene *scene, Object **objects, const uint objects_len, int action)
static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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)
BMFace ** ED_uvedit_selected_faces(Scene *scene, BMesh *bm, int len_max, int *r_faces_len)
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)
static void uv_select_all_perform(Scene *scene, Object *obedit, int action)
void UV_OT_select_overlap(wmOperatorType *ot)
#define IS_UNSEL
void UV_OT_select_lasso(wmOperatorType *ot)
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)
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)
static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select)
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)
static int uv_select_edgeloop(SpaceImage *sima, Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend)
static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, BMEditMesh *em, UvVertMap *vmap, const uint efa_index, BMLoop *l, const bool select, const int cd_loop_uv_offset)
bool uv_find_nearest_edge_multi(Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit)
void uvedit_face_select_set_with_sticky(const SpaceImage *sima, 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)
void ED_uvedit_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const bool select)
void uvedit_uv_select_set_with_sticky(const struct SpaceImage *sima, const Scene *scene, BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, const uint cd_loop_uv_offset)
static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
#define IS_SEL
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)
void UV_OT_select_less(wmOperatorType *ot)
void ED_uvedit_active_vert_loop_set(BMesh *bm, BMLoop *l)
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)
wmOperatorType * ot
Definition: wm_files.c:3156
bool WM_gesture_is_modal_first(const wmGesture *gesture)
Definition: wm_gesture.c:124
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)
static bool do_history(const char *name, ReportList *reports)
Definition: writefile.c:1079