userdef_defaults for 'Render In' and 'File Browser'
[blender.git] / source / blender / editors / uvedit / uvedit_ops.c
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
20 /** \file
21  * \ingroup eduv
22  */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27 #include <string.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "DNA_object_types.h"
32 #include "DNA_material_types.h"
33 #include "DNA_mesh_types.h"
34 #include "DNA_meshdata_types.h"
35 #include "DNA_node_types.h"
36 #include "DNA_image_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_scene_types.h"
39
40 #include "BLI_utildefines.h"
41 #include "BLI_alloca.h"
42 #include "BLI_math.h"
43 #include "BLI_lasso_2d.h"
44 #include "BLI_blenlib.h"
45 #include "BLI_array.h"
46 #include "BLI_hash.h"
47 #include "BLI_kdtree.h"
48 #include "BLI_kdopbvh.h"
49 #include "BLI_polyfill_2d.h"
50
51 #include "BLT_translation.h"
52
53 #include "BKE_context.h"
54 #include "BKE_customdata.h"
55 #include "BKE_editmesh.h"
56 #include "BKE_image.h"
57 #include "BKE_layer.h"
58 #include "BKE_main.h"
59 #include "BKE_material.h"
60 #include "BKE_mesh.h"
61 #include "BKE_mesh_mapping.h"
62 #include "BKE_node.h"
63 #include "BKE_report.h"
64 #include "BKE_scene.h"
65
66 #include "DEG_depsgraph.h"
67 #include "DEG_depsgraph_query.h"
68
69 #include "ED_image.h"
70 #include "ED_mesh.h"
71 #include "ED_node.h"
72 #include "ED_uvedit.h"
73 #include "ED_object.h"
74 #include "ED_screen.h"
75 #include "ED_select_utils.h"
76 #include "ED_transform.h"
77
78 #include "RNA_access.h"
79 #include "RNA_define.h"
80 #include "RNA_enum_types.h"
81
82 #include "WM_api.h"
83 #include "WM_types.h"
84
85 #include "UI_interface.h"
86 #include "UI_resources.h"
87 #include "UI_view2d.h"
88
89 #include "uvedit_intern.h"
90
91 static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit);
92 static bool uv_select_is_any_selected_multi(Scene *scene,
93                                             Image *ima,
94                                             Object **objects,
95                                             const uint objects_len);
96 static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
97 static void uv_select_all_perform_multi(
98     Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
99 static void uv_select_flush_from_tag_face(SpaceImage *sima,
100                                           Scene *scene,
101                                           Object *obedit,
102                                           const bool select);
103 static void uv_select_flush_from_tag_loop(SpaceImage *sima,
104                                           Scene *scene,
105                                           Object *obedit,
106                                           const bool select);
107 static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
108                                             const ToolSettings *ts,
109                                             Object *obedit);
110
111 /* -------------------------------------------------------------------- */
112 /** \name State Testing
113  * \{ */
114
115 bool ED_uvedit_test(Object *obedit)
116 {
117   BMEditMesh *em;
118   int ret;
119
120   if (!obedit) {
121     return 0;
122   }
123
124   if (obedit->type != OB_MESH) {
125     return 0;
126   }
127
128   em = BKE_editmesh_from_object(obedit);
129   ret = EDBM_uv_check(em);
130
131   return ret;
132 }
133
134 static int UNUSED_FUNCTION(ED_operator_uvmap_mesh)(bContext *C)
135 {
136   Object *ob = CTX_data_active_object(C);
137
138   if (ob && ob->type == OB_MESH) {
139     Mesh *me = ob->data;
140
141     if (CustomData_get_layer(&me->ldata, CD_MLOOPUV) != NULL) {
142       return 1;
143     }
144   }
145
146   return 0;
147 }
148
149 /** \} */
150
151 /* -------------------------------------------------------------------- */
152 /** \name Object Active Image
153  * \{ */
154
155 static bool is_image_texture_node(bNode *node)
156 {
157   return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
158 }
159
160 bool ED_object_get_active_image(Object *ob,
161                                 int mat_nr,
162                                 Image **r_ima,
163                                 ImageUser **r_iuser,
164                                 bNode **r_node,
165                                 bNodeTree **r_ntree)
166 {
167   Material *ma = give_current_material(ob, mat_nr);
168   bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
169   bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL;
170
171   if (node && is_image_texture_node(node)) {
172     if (r_ima) {
173       *r_ima = (Image *)node->id;
174     }
175     if (r_iuser) {
176       if (node->type == SH_NODE_TEX_IMAGE) {
177         *r_iuser = &((NodeTexImage *)node->storage)->iuser;
178       }
179       else if (node->type == SH_NODE_TEX_ENVIRONMENT) {
180         *r_iuser = &((NodeTexEnvironment *)node->storage)->iuser;
181       }
182       else {
183         *r_iuser = NULL;
184       }
185     }
186     if (r_node) {
187       *r_node = node;
188     }
189     if (r_ntree) {
190       *r_ntree = ntree;
191     }
192     return true;
193   }
194
195   if (r_ima) {
196     *r_ima = NULL;
197   }
198   if (r_iuser) {
199     *r_iuser = NULL;
200   }
201   if (r_node) {
202     *r_node = node;
203   }
204   if (r_ntree) {
205     *r_ntree = ntree;
206   }
207
208   return false;
209 }
210
211 void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
212 {
213   Material *ma = give_current_material(ob, mat_nr);
214   bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
215
216   if (node && is_image_texture_node(node)) {
217     node->id = &ima->id;
218     ED_node_tag_update_nodetree(bmain, ma->nodetree, node);
219   }
220 }
221
222 /** \} */
223
224 /* -------------------------------------------------------------------- */
225 /** \name Space Conversion
226  * \{ */
227
228 static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
229 {
230   int width, height;
231
232   if (sima) {
233     ED_space_image_get_size(sima, &width, &height);
234   }
235   else {
236     width = IMG_SIZE_FALLBACK;
237     height = IMG_SIZE_FALLBACK;
238   }
239
240   dist[0] = pixeldist / width;
241   dist[1] = pixeldist / height;
242 }
243
244 /** \} */
245
246 /* -------------------------------------------------------------------- */
247 /** \name Visibility and Selection Utilities
248  * \{ */
249
250 static void uvedit_vertex_select_tagged(BMEditMesh *em,
251                                         Scene *scene,
252                                         bool select,
253                                         int cd_loop_uv_offset)
254 {
255   BMFace *efa;
256   BMLoop *l;
257   BMIter iter, liter;
258
259   BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
260     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
261       if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
262         uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
263       }
264     }
265   }
266 }
267
268 bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
269 {
270   if (ts->uv_flag & UV_SYNC_SELECTION) {
271     return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
272   }
273   else {
274     return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
275   }
276 }
277 bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
278 {
279   return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
280 }
281
282 bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa)
283 {
284   if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
285     Image *face_image;
286     ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL);
287     return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false;
288   }
289   else {
290     return uvedit_face_visible_nolocal_ex(ts, efa);
291   }
292 }
293 bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *efa)
294 {
295   return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa);
296 }
297
298 bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
299 {
300   if (ts->uv_flag & UV_SYNC_SELECTION) {
301     return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
302   }
303   else {
304     BMLoop *l;
305     MLoopUV *luv;
306     BMIter liter;
307
308     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
309       luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
310       if (!(luv->flag & MLOOPUV_VERTSEL)) {
311         return false;
312       }
313     }
314
315     return true;
316   }
317 }
318 bool uvedit_face_select_test(Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
319 {
320   return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
321 }
322
323 bool uvedit_face_select_set(struct Scene *scene,
324                             struct BMEditMesh *em,
325                             struct BMFace *efa,
326                             const bool select,
327                             const bool do_history,
328                             const int cd_loop_uv_offset)
329 {
330   if (select) {
331     return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
332   }
333   else {
334     return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
335   }
336 }
337
338 bool uvedit_face_select_enable(
339     Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, const int cd_loop_uv_offset)
340 {
341   ToolSettings *ts = scene->toolsettings;
342
343   if (ts->uv_flag & UV_SYNC_SELECTION) {
344     BM_face_select_set(em->bm, efa, true);
345     if (do_history) {
346       BM_select_history_store(em->bm, (BMElem *)efa);
347     }
348   }
349   else {
350     BMLoop *l;
351     MLoopUV *luv;
352     BMIter liter;
353
354     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
355       luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
356       luv->flag |= MLOOPUV_VERTSEL;
357     }
358
359     return true;
360   }
361
362   return false;
363 }
364
365 bool uvedit_face_select_disable(Scene *scene,
366                                 BMEditMesh *em,
367                                 BMFace *efa,
368                                 const int cd_loop_uv_offset)
369 {
370   ToolSettings *ts = scene->toolsettings;
371
372   if (ts->uv_flag & UV_SYNC_SELECTION) {
373     BM_face_select_set(em->bm, efa, false);
374   }
375   else {
376     BMLoop *l;
377     MLoopUV *luv;
378     BMIter liter;
379
380     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
381       luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
382       luv->flag &= ~MLOOPUV_VERTSEL;
383     }
384
385     return true;
386   }
387
388   return false;
389 }
390
391 bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
392 {
393   if (ts->uv_flag & UV_SYNC_SELECTION) {
394     if (ts->selectmode & SCE_SELECT_FACE) {
395       return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
396     }
397     else if (ts->selectmode == SCE_SELECT_EDGE) {
398       return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
399     }
400     else {
401       return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
402              BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
403     }
404   }
405   else {
406     MLoopUV *luv1, *luv2;
407
408     luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
409     luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
410
411     return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
412   }
413 }
414 bool uvedit_edge_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
415 {
416   return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
417 }
418
419 void uvedit_edge_select_set(BMEditMesh *em,
420                             Scene *scene,
421                             BMLoop *l,
422                             const bool select,
423                             const bool do_history,
424                             const int cd_loop_uv_offset)
425
426 {
427   if (select) {
428     uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
429   }
430   else {
431     uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
432   }
433 }
434
435 void uvedit_edge_select_enable(
436     BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
437
438 {
439   ToolSettings *ts = scene->toolsettings;
440
441   if (ts->uv_flag & UV_SYNC_SELECTION) {
442     if (ts->selectmode & SCE_SELECT_FACE) {
443       BM_face_select_set(em->bm, l->f, true);
444     }
445     else if (ts->selectmode & SCE_SELECT_EDGE) {
446       BM_edge_select_set(em->bm, l->e, true);
447     }
448     else {
449       BM_vert_select_set(em->bm, l->e->v1, true);
450       BM_vert_select_set(em->bm, l->e->v2, true);
451     }
452
453     if (do_history) {
454       BM_select_history_store(em->bm, (BMElem *)l->e);
455     }
456   }
457   else {
458     MLoopUV *luv1, *luv2;
459
460     luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
461     luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
462
463     luv1->flag |= MLOOPUV_VERTSEL;
464     luv2->flag |= MLOOPUV_VERTSEL;
465   }
466 }
467
468 void uvedit_edge_select_disable(BMEditMesh *em,
469                                 Scene *scene,
470                                 BMLoop *l,
471                                 const int cd_loop_uv_offset)
472
473 {
474   ToolSettings *ts = scene->toolsettings;
475
476   if (ts->uv_flag & UV_SYNC_SELECTION) {
477     if (ts->selectmode & SCE_SELECT_FACE) {
478       BM_face_select_set(em->bm, l->f, false);
479     }
480     else if (ts->selectmode & SCE_SELECT_EDGE) {
481       BM_edge_select_set(em->bm, l->e, false);
482     }
483     else {
484       BM_vert_select_set(em->bm, l->e->v1, false);
485       BM_vert_select_set(em->bm, l->e->v2, false);
486     }
487   }
488   else {
489     MLoopUV *luv1, *luv2;
490
491     luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
492     luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
493
494     luv1->flag &= ~MLOOPUV_VERTSEL;
495     luv2->flag &= ~MLOOPUV_VERTSEL;
496   }
497 }
498
499 bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
500 {
501   if (ts->uv_flag & UV_SYNC_SELECTION) {
502     if (ts->selectmode & SCE_SELECT_FACE) {
503       return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
504     }
505     else {
506       return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
507     }
508   }
509   else {
510     MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
511     return (luv->flag & MLOOPUV_VERTSEL) != 0;
512   }
513 }
514 bool uvedit_uv_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
515 {
516   return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
517 }
518
519 void uvedit_uv_select_set(BMEditMesh *em,
520                           Scene *scene,
521                           BMLoop *l,
522                           const bool select,
523                           const bool do_history,
524                           const int cd_loop_uv_offset)
525 {
526   if (select) {
527     uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
528   }
529   else {
530     uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
531   }
532 }
533
534 void uvedit_uv_select_enable(
535     BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
536 {
537   ToolSettings *ts = scene->toolsettings;
538
539   if (ts->uv_flag & UV_SYNC_SELECTION) {
540     if (ts->selectmode & SCE_SELECT_FACE) {
541       BM_face_select_set(em->bm, l->f, true);
542     }
543     else {
544       BM_vert_select_set(em->bm, l->v, true);
545     }
546
547     if (do_history) {
548       BM_select_history_remove(em->bm, (BMElem *)l->v);
549     }
550   }
551   else {
552     MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
553     luv->flag |= MLOOPUV_VERTSEL;
554   }
555 }
556
557 void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
558 {
559   ToolSettings *ts = scene->toolsettings;
560
561   if (ts->uv_flag & UV_SYNC_SELECTION) {
562     if (ts->selectmode & SCE_SELECT_FACE) {
563       BM_face_select_set(em->bm, l->f, false);
564     }
565     else {
566       BM_vert_select_set(em->bm, l->v, false);
567     }
568   }
569   else {
570     MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
571     luv->flag &= ~MLOOPUV_VERTSEL;
572   }
573 }
574
575 /** \} */
576
577 /* -------------------------------------------------------------------- */
578 /** \name Live Unwrap Utilities
579  * \{ */
580
581 void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
582 {
583   if (sima && (sima->flag & SI_LIVE_UNWRAP)) {
584     ED_uvedit_live_unwrap_begin(scene, obedit);
585     ED_uvedit_live_unwrap_re_solve();
586     ED_uvedit_live_unwrap_end(0);
587   }
588 }
589
590 /** \} */
591
592 /* -------------------------------------------------------------------- */
593 /** \name Geometric Utilities
594  * \{ */
595
596 void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset)
597 {
598   BMLoop *l;
599   MLoopUV *luv;
600   BMIter liter;
601
602   zero_v2(r_cent);
603
604   BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
605     luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
606     add_v2_v2(r_cent, luv->uv);
607   }
608
609   mul_v2_fl(r_cent, 1.0f / (float)f->len);
610 }
611
612 void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
613 {
614   int i;
615   for (i = 0; i < len; i++) {
616     uv[i][0] = uv_orig[i][0] * aspx;
617     uv[i][1] = uv_orig[i][1] * aspy;
618   }
619 }
620
621 bool ED_uvedit_minmax_multi(Scene *scene,
622                             Image *ima,
623                             Object **objects_edit,
624                             uint objects_len,
625                             float r_min[2],
626                             float r_max[2])
627 {
628   bool changed = false;
629   INIT_MINMAX2(r_min, r_max);
630
631   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
632     Object *obedit = objects_edit[ob_index];
633
634     BMEditMesh *em = BKE_editmesh_from_object(obedit);
635     BMFace *efa;
636     BMLoop *l;
637     BMIter iter, liter;
638     MLoopUV *luv;
639
640     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
641
642     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
643       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
644         continue;
645       }
646
647       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
648         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
649           luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
650           minmax_v2v2_v2(r_min, r_max, luv->uv);
651           changed = true;
652         }
653       }
654     }
655   }
656   return changed;
657 }
658
659 bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
660 {
661   return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max);
662 }
663
664 /* Be careful when using this, it bypasses all synchronization options */
665 void ED_uvedit_select_all(BMesh *bm)
666 {
667   BMFace *efa;
668   BMLoop *l;
669   BMIter iter, liter;
670   MLoopUV *luv;
671
672   const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
673
674   BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
675     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
676       luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
677       luv->flag |= MLOOPUV_VERTSEL;
678     }
679   }
680 }
681
682 static bool ED_uvedit_median_multi(
683     Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
684 {
685   unsigned int sel = 0;
686   zero_v2(co);
687
688   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
689     Object *obedit = objects_edit[ob_index];
690
691     BMEditMesh *em = BKE_editmesh_from_object(obedit);
692     BMFace *efa;
693     BMLoop *l;
694     BMIter iter, liter;
695     MLoopUV *luv;
696
697     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
698
699     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
700       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
701         continue;
702       }
703
704       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
705         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
706         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
707           add_v2_v2(co, luv->uv);
708           sel++;
709         }
710       }
711     }
712   }
713
714   mul_v2_fl(co, 1.0f / (float)sel);
715
716   return (sel != 0);
717 }
718
719 static bool UNUSED_FUNCTION(ED_uvedit_median)(Scene *scene,
720                                               Image *ima,
721                                               Object *obedit,
722                                               float co[2])
723 {
724   return ED_uvedit_median_multi(scene, ima, &obedit, 1, co);
725 }
726
727 bool ED_uvedit_center_multi(
728     Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float cent[2], char mode)
729 {
730   bool changed = false;
731
732   if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
733     float min[2], max[2];
734     if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) {
735       mid_v2_v2v2(cent, min, max);
736       changed = true;
737     }
738   }
739   else {
740     if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) {
741       changed = true;
742     }
743   }
744
745   return changed;
746 }
747
748 bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
749 {
750   return ED_uvedit_center_multi(scene, ima, &obedit, 1, cent, mode);
751 }
752
753 /** \} */
754
755 /* -------------------------------------------------------------------- */
756 /** \name Find Nearest Elements
757  * \{ */
758
759 bool uv_find_nearest_edge(
760     Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit)
761 {
762   BMEditMesh *em = BKE_editmesh_from_object(obedit);
763   BMFace *efa;
764   BMLoop *l;
765   BMIter iter, liter;
766   MLoopUV *luv, *luv_next;
767   int i;
768   bool found = false;
769
770   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
771
772   BM_mesh_elem_index_ensure(em->bm, BM_VERT);
773
774   BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
775     if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
776       continue;
777     }
778     BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
779       luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
780       luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
781
782       const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
783
784       if (dist_test_sq < hit->dist_sq) {
785         hit->efa = efa;
786
787         hit->l = l;
788         hit->luv = luv;
789         hit->luv_next = luv_next;
790         hit->lindex = i;
791
792         hit->dist_sq = dist_test_sq;
793         found = true;
794       }
795     }
796   }
797   return found;
798 }
799
800 bool uv_find_nearest_edge_multi(Scene *scene,
801                                 Image *ima,
802                                 Object **objects,
803                                 const uint objects_len,
804                                 const float co[2],
805                                 UvNearestHit *hit_final)
806 {
807   bool found = false;
808   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
809     Object *obedit = objects[ob_index];
810     if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
811       hit_final->ob = obedit;
812       found = true;
813     }
814   }
815   return found;
816 }
817
818 bool uv_find_nearest_face(
819     Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final)
820 {
821   BMEditMesh *em = BKE_editmesh_from_object(obedit);
822   bool found = false;
823
824   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
825
826   /* this will fill in hit.vert1 and hit.vert2 */
827   float dist_sq_init = hit_final->dist_sq;
828   UvNearestHit hit = *hit_final;
829   if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
830     hit.dist_sq = dist_sq_init;
831     hit.l = NULL;
832     hit.luv = hit.luv_next = NULL;
833
834     BMIter iter;
835     BMFace *efa;
836
837     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
838       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
839         continue;
840       }
841
842       float cent[2];
843       uv_poly_center(efa, cent, cd_loop_uv_offset);
844
845       const float dist_test_sq = len_squared_v2v2(co, cent);
846
847       if (dist_test_sq < hit.dist_sq) {
848         hit.efa = efa;
849         hit.dist_sq = dist_test_sq;
850         found = true;
851       }
852     }
853   }
854   if (found) {
855     *hit_final = hit;
856   }
857   return found;
858 }
859
860 bool uv_find_nearest_face_multi(Scene *scene,
861                                 Image *ima,
862                                 Object **objects,
863                                 const uint objects_len,
864                                 const float co[2],
865                                 UvNearestHit *hit_final)
866 {
867   bool found = false;
868   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
869     Object *obedit = objects[ob_index];
870     if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
871       hit_final->ob = obedit;
872       found = true;
873     }
874   }
875   return found;
876 }
877
878 static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
879 {
880   const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
881   const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
882   const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
883
884   return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
885           (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
886 }
887
888 bool uv_find_nearest_vert(Scene *scene,
889                           Image *ima,
890                           Object *obedit,
891                           float const co[2],
892                           const float penalty_dist,
893                           UvNearestHit *hit_final)
894 {
895   bool found = false;
896
897   /* this will fill in hit.vert1 and hit.vert2 */
898   float dist_sq_init = hit_final->dist_sq;
899   UvNearestHit hit = *hit_final;
900   if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
901     hit.dist_sq = dist_sq_init;
902
903     hit.l = NULL;
904     hit.luv = hit.luv_next = NULL;
905
906     BMEditMesh *em = BKE_editmesh_from_object(obedit);
907     BMFace *efa;
908     BMIter iter;
909
910     BM_mesh_elem_index_ensure(em->bm, BM_VERT);
911
912     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
913
914     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
915       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
916         continue;
917       }
918
919       BMIter liter;
920       BMLoop *l;
921       int i;
922       BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
923         float dist_test_sq;
924         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
925         if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
926           dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
927           dist_test_sq = SQUARE(dist_test_sq);
928         }
929         else {
930           dist_test_sq = len_squared_v2v2(co, luv->uv);
931         }
932
933         if (dist_test_sq <= hit.dist_sq) {
934           if (dist_test_sq == hit.dist_sq) {
935             if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
936               continue;
937             }
938           }
939
940           hit.dist_sq = dist_test_sq;
941
942           hit.l = l;
943           hit.luv = luv;
944           hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
945           hit.efa = efa;
946           hit.lindex = i;
947           found = true;
948         }
949       }
950     }
951   }
952
953   if (found) {
954     *hit_final = hit;
955   }
956
957   return found;
958 }
959
960 bool uv_find_nearest_vert_multi(Scene *scene,
961                                 Image *ima,
962                                 Object **objects,
963                                 const uint objects_len,
964                                 float const co[2],
965                                 const float penalty_dist,
966                                 UvNearestHit *hit_final)
967 {
968   bool found = false;
969   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
970     Object *obedit = objects[ob_index];
971     if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
972       hit_final->ob = obedit;
973       found = true;
974     }
975   }
976   return found;
977 }
978
979 bool ED_uvedit_nearest_uv(
980     Scene *scene, Object *obedit, Image *ima, const float co[2], float *dist_sq, float r_uv[2])
981 {
982   BMEditMesh *em = BKE_editmesh_from_object(obedit);
983   BMIter iter;
984   BMFace *efa;
985   const float *uv_best = NULL;
986   float dist_best = *dist_sq;
987   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
988   BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
989     if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
990       continue;
991     }
992     BMLoop *l_iter, *l_first;
993     l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
994     do {
995       const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
996       const float dist_test = len_squared_v2v2(co, uv);
997       if (dist_best > dist_test) {
998         dist_best = dist_test;
999         uv_best = uv;
1000       }
1001     } while ((l_iter = l_iter->next) != l_first);
1002   }
1003
1004   if (uv_best != NULL) {
1005     copy_v2_v2(r_uv, uv_best);
1006     *dist_sq = dist_best;
1007     return true;
1008   }
1009   else {
1010     return false;
1011   }
1012 }
1013
1014 bool ED_uvedit_nearest_uv_multi(Scene *scene,
1015                                 Image *ima,
1016                                 Object **objects,
1017                                 const uint objects_len,
1018                                 const float co[2],
1019                                 float *dist_sq,
1020                                 float r_uv[2])
1021 {
1022   bool found = false;
1023   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1024     Object *obedit = objects[ob_index];
1025     if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) {
1026       found = true;
1027     }
1028   }
1029   return found;
1030 }
1031
1032 /** \} */
1033
1034 /* -------------------------------------------------------------------- */
1035 /** \name Loop Select
1036  * \{ */
1037
1038 static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
1039 {
1040   UvMapVert *iterv;
1041   int count = 0;
1042
1043   for (iterv = first; iterv; iterv = iterv->next) {
1044     if (iterv->separate && iterv != first) {
1045       break;
1046     }
1047
1048     count++;
1049   }
1050
1051   if (count < 5) {
1052     first->flag = 1;
1053   }
1054 }
1055
1056 static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l)
1057 {
1058   UvMapVert *iterv, *first;
1059   first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
1060
1061   for (iterv = first; iterv; iterv = iterv->next) {
1062     if (iterv->separate) {
1063       first = iterv;
1064     }
1065     if (iterv->poly_index == BM_elem_index_get(efa)) {
1066       return first;
1067     }
1068   }
1069
1070   return NULL;
1071 }
1072
1073 static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em,
1074                                               UvMapVert *first1,
1075                                               UvMapVert *first2,
1076                                               int *totface)
1077 {
1078   UvMapVert *iterv1, *iterv2;
1079   BMFace *efa;
1080   int tot = 0;
1081
1082   /* count number of faces this edge has */
1083   for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
1084     if (iterv1->separate && iterv1 != first1) {
1085       break;
1086     }
1087
1088     for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
1089       if (iterv2->separate && iterv2 != first2) {
1090         break;
1091       }
1092
1093       if (iterv1->poly_index == iterv2->poly_index) {
1094         /* if face already tagged, don't do this edge */
1095         efa = BM_face_at_index(em->bm, iterv1->poly_index);
1096         if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
1097           return false;
1098         }
1099
1100         tot++;
1101         break;
1102       }
1103     }
1104   }
1105
1106   if (*totface == 0) { /* start edge */
1107     *totface = tot;
1108   }
1109   else if (tot != *totface) { /* check for same number of faces as start edge */
1110     return false;
1111   }
1112
1113   /* tag the faces */
1114   for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
1115     if (iterv1->separate && iterv1 != first1) {
1116       break;
1117     }
1118
1119     for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
1120       if (iterv2->separate && iterv2 != first2) {
1121         break;
1122       }
1123
1124       if (iterv1->poly_index == iterv2->poly_index) {
1125         efa = BM_face_at_index(em->bm, iterv1->poly_index);
1126         BM_elem_flag_enable(efa, BM_ELEM_TAG);
1127         break;
1128       }
1129     }
1130   }
1131
1132   return true;
1133 }
1134
1135 static int uv_select_edgeloop(Scene *scene,
1136                               Image *ima,
1137                               Object *obedit,
1138                               UvNearestHit *hit,
1139                               const float limit[2],
1140                               const bool extend)
1141 {
1142   BMEditMesh *em = BKE_editmesh_from_object(obedit);
1143   BMFace *efa;
1144   BMIter iter, liter;
1145   BMLoop *l;
1146   UvVertMap *vmap;
1147   UvMapVert *iterv_curr;
1148   UvMapVert *iterv_next;
1149   int starttotf;
1150   bool looking, select;
1151
1152   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1153
1154   /* setup */
1155   BM_mesh_elem_table_ensure(em->bm, BM_FACE);
1156   vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
1157
1158   BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
1159
1160   if (!extend) {
1161     uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
1162   }
1163
1164   BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
1165
1166   /* set flags for first face and verts */
1167   iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
1168   iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
1169   uv_select_edgeloop_vertex_loop_flag(iterv_curr);
1170   uv_select_edgeloop_vertex_loop_flag(iterv_next);
1171
1172   starttotf = 0;
1173   uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
1174
1175   /* sorry, first edge isn't even ok */
1176   looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
1177
1178   /* iterate */
1179   while (looking) {
1180     looking = false;
1181
1182     /* find correct valence edges which are not tagged yet, but connect to tagged one */
1183
1184     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1185       if (!BM_elem_flag_test(efa, BM_ELEM_TAG) &&
1186           uvedit_face_visible_test(scene, obedit, ima, efa)) {
1187         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1188           /* check face not hidden and not tagged */
1189           if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) {
1190             continue;
1191           }
1192           if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) {
1193             continue;
1194           }
1195
1196           /* check if vertex is tagged and has right valence */
1197           if (iterv_curr->flag || iterv_next->flag) {
1198             if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
1199               looking = true;
1200               BM_elem_flag_enable(efa, BM_ELEM_TAG);
1201
1202               uv_select_edgeloop_vertex_loop_flag(iterv_curr);
1203               uv_select_edgeloop_vertex_loop_flag(iterv_next);
1204               break;
1205             }
1206           }
1207         }
1208       }
1209     }
1210   }
1211
1212   /* do the actual select/deselect */
1213   iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
1214   iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
1215   iterv_curr->flag = 1;
1216   iterv_next->flag = 1;
1217
1218   if (extend) {
1219     select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
1220   }
1221   else {
1222     select = true;
1223   }
1224
1225   BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1226     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1227       iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
1228
1229       if (iterv_curr->flag) {
1230         uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
1231       }
1232     }
1233   }
1234
1235   /* cleanup */
1236   BM_uv_vert_map_free(vmap);
1237
1238   return (select) ? 1 : -1;
1239 }
1240
1241 /** \} */
1242
1243 /* -------------------------------------------------------------------- */
1244 /** \name Select Linked
1245  * \{ */
1246
1247 static void uv_select_linked_multi(Scene *scene,
1248                                    Image *ima,
1249                                    Object **objects,
1250                                    const uint objects_len,
1251                                    const float limit[2],
1252                                    UvNearestHit *hit_final,
1253                                    bool extend,
1254                                    bool deselect,
1255                                    bool toggle,
1256                                    bool select_faces)
1257 {
1258   /* loop over objects, or just use hit_final->ob */
1259   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1260     if (hit_final && ob_index != 0) {
1261       break;
1262     }
1263     Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
1264
1265     BMFace *efa;
1266     BMLoop *l;
1267     BMIter iter, liter;
1268     MLoopUV *luv;
1269     UvVertMap *vmap;
1270     UvMapVert *vlist, *iterv, *startv;
1271     int i, stacksize = 0, *stack;
1272     unsigned int a;
1273     char *flag;
1274
1275     BMEditMesh *em = BKE_editmesh_from_object(obedit);
1276     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1277
1278     BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
1279
1280     /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
1281      * this made *every* projection split the island into front/back islands.
1282      * Keep 'use_winding' to false, see: T50970.
1283      *
1284      * Better solve this by having a delimit option for select-linked operator,
1285      * keeping island-select working as is. */
1286     vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
1287
1288     if (vmap == NULL) {
1289       return;
1290     }
1291
1292     stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
1293     flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
1294
1295     if (hit_final == NULL) {
1296       /* Use existing selection */
1297       BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1298         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
1299           if (select_faces) {
1300             if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1301               stack[stacksize] = a;
1302               stacksize++;
1303               flag[a] = 1;
1304             }
1305           }
1306           else {
1307             BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1308               luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1309
1310               if (luv->flag & MLOOPUV_VERTSEL) {
1311                 stack[stacksize] = a;
1312                 stacksize++;
1313                 flag[a] = 1;
1314
1315                 break;
1316               }
1317             }
1318           }
1319         }
1320       }
1321     }
1322     else {
1323       BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1324         if (efa == hit_final->efa) {
1325           stack[stacksize] = a;
1326           stacksize++;
1327           flag[a] = 1;
1328           break;
1329         }
1330       }
1331     }
1332
1333     while (stacksize > 0) {
1334
1335       stacksize--;
1336       a = stack[stacksize];
1337
1338       efa = BM_face_at_index(em->bm, a);
1339
1340       BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1341
1342         /* make_uv_vert_map_EM sets verts tmp.l to the indices */
1343         vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
1344
1345         startv = vlist;
1346
1347         for (iterv = vlist; iterv; iterv = iterv->next) {
1348           if (iterv->separate) {
1349             startv = iterv;
1350           }
1351           if (iterv->poly_index == a) {
1352             break;
1353           }
1354         }
1355
1356         for (iterv = startv; iterv; iterv = iterv->next) {
1357           if ((startv != iterv) && (iterv->separate)) {
1358             break;
1359           }
1360           else if (!flag[iterv->poly_index]) {
1361             flag[iterv->poly_index] = 1;
1362             stack[stacksize] = iterv->poly_index;
1363             stacksize++;
1364           }
1365         }
1366       }
1367     }
1368
1369     /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
1370     if ((toggle == true) && (extend == false) && (deselect == false)) {
1371       BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1372         bool found_selected = false;
1373         if (!flag[a]) {
1374           continue;
1375         }
1376
1377         if (select_faces) {
1378           if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
1379             found_selected = true;
1380           }
1381         }
1382         else {
1383           BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1384             luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1385
1386             if (luv->flag & MLOOPUV_VERTSEL) {
1387               found_selected = true;
1388             }
1389           }
1390
1391           if (found_selected) {
1392             deselect = true;
1393             break;
1394           }
1395         }
1396       }
1397     }
1398
1399 #define SET_SELECTION(value) \
1400   if (select_faces) { \
1401     BM_face_select_set(em->bm, efa, value); \
1402   } \
1403   else { \
1404     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
1405       luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
1406       luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
1407     } \
1408   } \
1409   (void)0
1410
1411     BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1412       if (!flag[a]) {
1413         if (!extend && !deselect && !toggle) {
1414           SET_SELECTION(false);
1415         }
1416         continue;
1417       }
1418
1419       if (!deselect) {
1420         SET_SELECTION(true);
1421       }
1422       else {
1423         SET_SELECTION(false);
1424       }
1425     }
1426
1427 #undef SET_SELECTION
1428
1429     MEM_freeN(stack);
1430     MEM_freeN(flag);
1431     BM_uv_vert_map_free(vmap);
1432   }
1433 }
1434
1435 /* WATCH IT: this returns first selected UV,
1436  * not ideal in many cases since there could be multiple */
1437 static float *uv_sel_co_from_eve(
1438     Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve)
1439 {
1440   BMIter liter;
1441   BMLoop *l;
1442
1443   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1444
1445   BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
1446     if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
1447       continue;
1448     }
1449
1450     if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1451       MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1452       return luv->uv;
1453     }
1454   }
1455
1456   return NULL;
1457 }
1458
1459 /** \} */
1460
1461 /* -------------------------------------------------------------------- */
1462 /** \name Select More/Less Operator
1463  * \{ */
1464
1465 static int uv_select_more_less(bContext *C, const bool select)
1466 {
1467   Scene *scene = CTX_data_scene(C);
1468   ViewLayer *view_layer = CTX_data_view_layer(C);
1469   Image *ima = CTX_data_edit_image(C);
1470   SpaceImage *sima = CTX_wm_space_image(C);
1471
1472   BMFace *efa;
1473   BMLoop *l;
1474   BMIter iter, liter;
1475   ToolSettings *ts = scene->toolsettings;
1476
1477   uint objects_len = 0;
1478   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
1479       view_layer, ((View3D *)NULL), &objects_len);
1480
1481   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1482     Object *obedit = objects[ob_index];
1483     BMEditMesh *em = BKE_editmesh_from_object(obedit);
1484
1485     bool changed = false;
1486
1487     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1488
1489     if (ts->uv_flag & UV_SYNC_SELECTION) {
1490       if (select) {
1491         EDBM_select_more(em, true);
1492       }
1493       else {
1494         EDBM_select_less(em, true);
1495       }
1496
1497       DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
1498       WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1499       continue;
1500     }
1501
1502     if (ts->uv_selectmode == UV_SELECT_FACE) {
1503
1504       /* clear tags */
1505       BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
1506
1507       /* mark loops to be selected */
1508       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1509         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
1510
1511 #define IS_SEL 1
1512 #define IS_UNSEL 2
1513
1514           int sel_state = 0;
1515
1516           BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1517             MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1518             if (luv->flag & MLOOPUV_VERTSEL) {
1519               sel_state |= IS_SEL;
1520             }
1521             else {
1522               sel_state |= IS_UNSEL;
1523             }
1524
1525             /* if we have a mixed selection, tag to grow it */
1526             if (sel_state == (IS_SEL | IS_UNSEL)) {
1527               BM_elem_flag_enable(efa, BM_ELEM_TAG);
1528               changed = true;
1529               break;
1530             }
1531           }
1532
1533 #undef IS_SEL
1534 #undef IS_UNSEL
1535         }
1536       }
1537     }
1538     else {
1539
1540       /* clear tags */
1541       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1542         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1543           BM_elem_flag_disable(l, BM_ELEM_TAG);
1544         }
1545       }
1546
1547       /* mark loops to be selected */
1548       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1549         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
1550           BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1551
1552             MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1553
1554             if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
1555               BM_elem_flag_enable(l->next, BM_ELEM_TAG);
1556               BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
1557               changed = true;
1558             }
1559           }
1560         }
1561       }
1562     }
1563
1564     if (changed) {
1565       /* Select tagged loops. */
1566       uv_select_flush_from_tag_loop(sima, scene, obedit, select);
1567       DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
1568       WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1569     }
1570   }
1571   MEM_freeN(objects);
1572
1573   return OPERATOR_FINISHED;
1574 }
1575
1576 static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
1577 {
1578   return uv_select_more_less(C, true);
1579 }
1580
1581 static void UV_OT_select_more(wmOperatorType *ot)
1582 {
1583   /* identifiers */
1584   ot->name = "Select More";
1585   ot->description = "Select more UV vertices connected to initial selection";
1586   ot->idname = "UV_OT_select_more";
1587   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1588
1589   /* api callbacks */
1590   ot->exec = uv_select_more_exec;
1591   ot->poll = ED_operator_uvedit_space_image;
1592 }
1593
1594 static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
1595 {
1596   return uv_select_more_less(C, false);
1597 }
1598
1599 static void UV_OT_select_less(wmOperatorType *ot)
1600 {
1601   /* identifiers */
1602   ot->name = "Select Less";
1603   ot->description = "Deselect UV vertices at the boundary of each selection region";
1604   ot->idname = "UV_OT_select_less";
1605   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1606
1607   /* api callbacks */
1608   ot->exec = uv_select_less_exec;
1609   ot->poll = ED_operator_uvedit_space_image;
1610 }
1611
1612 /** \} */
1613
1614 /* -------------------------------------------------------------------- */
1615 /** \name Weld Align Operator
1616  * \{ */
1617
1618 typedef enum eUVWeldAlign {
1619   UV_STRAIGHTEN,
1620   UV_STRAIGHTEN_X,
1621   UV_STRAIGHTEN_Y,
1622   UV_ALIGN_AUTO,
1623   UV_ALIGN_X,
1624   UV_ALIGN_Y,
1625   UV_WELD,
1626 } eUVWeldAlign;
1627
1628 static void uv_weld_align(bContext *C, eUVWeldAlign tool)
1629 {
1630   Scene *scene = CTX_data_scene(C);
1631   ViewLayer *view_layer = CTX_data_view_layer(C);
1632   SpaceImage *sima = CTX_wm_space_image(C);
1633   Image *ima = CTX_data_edit_image(C);
1634   ToolSettings *ts = scene->toolsettings;
1635   const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1636   float cent[2], min[2], max[2];
1637
1638   INIT_MINMAX2(min, max);
1639
1640   uint objects_len = 0;
1641   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
1642       view_layer, ((View3D *)NULL), &objects_len);
1643
1644   if (tool == UV_ALIGN_AUTO) {
1645     for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1646       Object *obedit = objects[ob_index];
1647       BMEditMesh *em = BKE_editmesh_from_object(obedit);
1648
1649       if (synced_selection && (em->bm->totvertsel == 0)) {
1650         continue;
1651       }
1652
1653       const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1654
1655       BMIter iter, liter;
1656       BMFace *efa;
1657       BMLoop *l;
1658
1659       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1660         if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
1661           continue;
1662         }
1663
1664         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1665           if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1666             MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1667             minmax_v2v2_v2(min, max, luv->uv);
1668           }
1669         }
1670       }
1671     }
1672     tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X;
1673   }
1674
1675   ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0);
1676
1677   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1678     Object *obedit = objects[ob_index];
1679     BMEditMesh *em = BKE_editmesh_from_object(obedit);
1680     bool changed = false;
1681
1682     if (synced_selection && (em->bm->totvertsel == 0)) {
1683       continue;
1684     }
1685
1686     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1687
1688     if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
1689       BMIter iter, liter;
1690       BMFace *efa;
1691       BMLoop *l;
1692
1693       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1694         if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
1695           continue;
1696         }
1697
1698         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1699           if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1700             MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1701             luv->uv[0] = cent[0];
1702             changed = true;
1703           }
1704         }
1705       }
1706     }
1707
1708     if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
1709       BMIter iter, liter;
1710       BMFace *efa;
1711       BMLoop *l;
1712
1713       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1714         if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
1715           continue;
1716         }
1717
1718         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1719           if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1720             MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1721             luv->uv[1] = cent[1];
1722             changed = true;
1723           }
1724         }
1725       }
1726     }
1727
1728     if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) {
1729       BMEdge *eed;
1730       BMLoop *l;
1731       BMVert *eve;
1732       BMVert *eve_start;
1733       BMIter iter, liter, eiter;
1734
1735       /* clear tag */
1736       BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
1737
1738       /* tag verts with a selected UV */
1739       BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1740         BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
1741           if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
1742             continue;
1743           }
1744
1745           if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1746             BM_elem_flag_enable(eve, BM_ELEM_TAG);
1747             break;
1748           }
1749         }
1750       }
1751
1752       /* flush vertex tags to edges */
1753       BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1754         BM_elem_flag_set(
1755             eed,
1756             BM_ELEM_TAG,
1757             (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
1758       }
1759
1760       /* find a vertex with only one tagged edge */
1761       eve_start = NULL;
1762       BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1763         int tot_eed_tag = 0;
1764         BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
1765           if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
1766             tot_eed_tag++;
1767           }
1768         }
1769
1770         if (tot_eed_tag == 1) {
1771           eve_start = eve;
1772           break;
1773         }
1774       }
1775
1776       if (eve_start) {
1777         BMVert **eve_line = NULL;
1778         BMVert *eve_next = NULL;
1779         BLI_array_declare(eve_line);
1780         int i;
1781
1782         eve = eve_start;
1783
1784         /* walk over edges, building an array of verts in a line */
1785         while (eve) {
1786           BLI_array_append(eve_line, eve);
1787           /* don't touch again */
1788           BM_elem_flag_disable(eve, BM_ELEM_TAG);
1789
1790           eve_next = NULL;
1791
1792           /* find next eve */
1793           BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
1794             if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
1795               BMVert *eve_other = BM_edge_other_vert(eed, eve);
1796               if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
1797                 /* this is a tagged vert we didn't walk over yet, step onto it */
1798                 eve_next = eve_other;
1799                 break;
1800               }
1801             }
1802           }
1803
1804           eve = eve_next;
1805         }
1806
1807         /* now we have all verts, make into a line */
1808         if (BLI_array_len(eve_line) > 2) {
1809
1810           /* we know the returns from these must be valid */
1811           const float *uv_start = uv_sel_co_from_eve(scene, obedit, ima, em, eve_line[0]);
1812           const float *uv_end = uv_sel_co_from_eve(
1813               scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
1814           /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
1815           float a = 0.0f;
1816           eUVWeldAlign tool_local = tool;
1817
1818           if (tool_local == UV_STRAIGHTEN_X) {
1819             if (uv_start[1] == uv_end[1]) {
1820               tool_local = UV_STRAIGHTEN;
1821             }
1822             else {
1823               a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
1824             }
1825           }
1826           else if (tool_local == UV_STRAIGHTEN_Y) {
1827             if (uv_start[0] == uv_end[0]) {
1828               tool_local = UV_STRAIGHTEN;
1829             }
1830             else {
1831               a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
1832             }
1833           }
1834
1835           /* go over all verts except for endpoints */
1836           for (i = 0; i < BLI_array_len(eve_line); i++) {
1837             BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
1838               if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
1839                 continue;
1840               }
1841
1842               if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1843                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1844                 /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
1845                  * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
1846                  * Maybe this should be a BLI func? Or is it already existing?
1847                  * Could use interp_v2_v2v2, but not sure it's worth it here...*/
1848                 if (tool_local == UV_STRAIGHTEN_X) {
1849                   luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
1850                 }
1851                 else if (tool_local == UV_STRAIGHTEN_Y) {
1852                   luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
1853                 }
1854                 else {
1855                   closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
1856                 }
1857                 changed = true;
1858               }
1859             }
1860           }
1861         }
1862         else {
1863           /* error - not a line, needs 3+ points  */
1864         }
1865
1866         if (eve_line) {
1867           MEM_freeN(eve_line);
1868         }
1869       }
1870       else {
1871         /* error - cant find an endpoint */
1872       }
1873     }
1874
1875     if (changed) {
1876       uvedit_live_unwrap_update(sima, scene, obedit);
1877       DEG_id_tag_update(obedit->data, 0);
1878       WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1879     }
1880   }
1881
1882   MEM_freeN(objects);
1883 }
1884
1885 static int uv_align_exec(bContext *C, wmOperator *op)
1886 {
1887   uv_weld_align(C, RNA_enum_get(op->ptr, "axis"));
1888
1889   return OPERATOR_FINISHED;
1890 }
1891
1892 static void UV_OT_align(wmOperatorType *ot)
1893 {
1894   static const EnumPropertyItem axis_items[] = {
1895       {UV_STRAIGHTEN,
1896        "ALIGN_S",
1897        0,
1898        "Straighten",
1899        "Align UVs along the line defined by the endpoints"},
1900       {UV_STRAIGHTEN_X,
1901        "ALIGN_T",
1902        0,
1903        "Straighten X",
1904        "Align UVs along the line defined by the endpoints along the X axis"},
1905       {UV_STRAIGHTEN_Y,
1906        "ALIGN_U",
1907        0,
1908        "Straighten Y",
1909        "Align UVs along the line defined by the endpoints along the Y axis"},
1910       {UV_ALIGN_AUTO,
1911        "ALIGN_AUTO",
1912        0,
1913        "Align Auto",
1914        "Automatically choose the axis on which there is most alignment already"},
1915       {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
1916       {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
1917       {0, NULL, 0, NULL, NULL},
1918   };
1919
1920   /* identifiers */
1921   ot->name = "Align";
1922   ot->description = "Align selected UV vertices to an axis";
1923   ot->idname = "UV_OT_align";
1924   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1925
1926   /* api callbacks */
1927   ot->exec = uv_align_exec;
1928   ot->poll = ED_operator_uvedit;
1929
1930   /* properties */
1931   RNA_def_enum(
1932       ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on");
1933 }
1934
1935 /** \} */
1936
1937 /* -------------------------------------------------------------------- */
1938 /** \name Remove Doubles Operator
1939  * \{ */
1940
1941 static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
1942 {
1943   Scene *scene = CTX_data_scene(C);
1944   ViewLayer *view_layer = CTX_data_view_layer(C);
1945   SpaceImage *sima = CTX_wm_space_image(C);
1946   Image *ima = CTX_data_edit_image(C);
1947   ToolSettings *ts = scene->toolsettings;
1948
1949   const float threshold = RNA_float_get(op->ptr, "threshold");
1950   const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1951
1952   uint objects_len = 0;
1953   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
1954       view_layer, ((View3D *)NULL), &objects_len);
1955
1956   bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed");
1957
1958   /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr.
1959    * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */
1960   uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len,
1961                                          "uv_remove_doubles_selected.ob_mloopuv_max_idx");
1962
1963   /* Calculate max possible number of kdtree nodes. */
1964   int uv_maxlen = 0;
1965   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1966     Object *obedit = objects[ob_index];
1967     BMEditMesh *em = BKE_editmesh_from_object(obedit);
1968
1969     if (synced_selection && (em->bm->totvertsel == 0)) {
1970       continue;
1971     }
1972
1973     uv_maxlen += em->bm->totloop;
1974   }
1975
1976   KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
1977
1978   int *duplicates = NULL;
1979   BLI_array_declare(duplicates);
1980
1981   MLoopUV **mloopuv_arr = NULL;
1982   BLI_array_declare(mloopuv_arr);
1983
1984   int mloopuv_count = 0; /* Also used for *duplicates count. */
1985
1986   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1987     BMIter iter, liter;
1988     BMFace *efa;
1989     BMLoop *l;
1990     Object *obedit = objects[ob_index];
1991     BMEditMesh *em = BKE_editmesh_from_object(obedit);
1992
1993     if (synced_selection && (em->bm->totvertsel == 0)) {
1994       continue;
1995     }
1996
1997     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1998
1999     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2000       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
2001         continue;
2002       }
2003
2004       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2005         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
2006           MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2007           BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
2008           BLI_array_append(duplicates, -1);
2009           BLI_array_append(mloopuv_arr, luv);
2010           mloopuv_count++;
2011         }
2012       }
2013     }
2014
2015     ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1;
2016   }
2017
2018   BLI_kdtree_2d_balance(tree);
2019   int found_duplicates = BLI_kdtree_2d_calc_duplicates_fast(tree, threshold, false, duplicates);
2020
2021   if (found_duplicates > 0) {
2022     /* Calculate average uv for duplicates. */
2023     int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count,
2024                                           "uv_remove_doubles_selected.uv_duplicate_count");
2025     for (int i = 0; i < mloopuv_count; i++) {
2026       if (duplicates[i] == -1) { /* If doesn't reference another */
2027         uv_duplicate_count[i]++; /* self */
2028         continue;
2029       }
2030
2031       if (duplicates[i] != i) {
2032         /* If not self then accumulate uv for averaging.
2033          * Self uv is already present in accumulator */
2034         add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv);
2035       }
2036       uv_duplicate_count[duplicates[i]]++;
2037     }
2038
2039     for (int i = 0; i < mloopuv_count; i++) {
2040       if (uv_duplicate_count[i] < 2) {
2041         continue;
2042       }
2043
2044       mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]);
2045     }
2046     MEM_freeN(uv_duplicate_count);
2047
2048     /* Update duplicated uvs. */
2049     uint ob_index = 0;
2050     for (int i = 0; i < mloopuv_count; i++) {
2051       /* Make sure we know which object owns the MLoopUV at this index.
2052        * Remember that in some cases the object will have no loop uv,
2053        * thus we need the while loop, and not simply an if check. */
2054       while (ob_mloopuv_max_idx[ob_index] < i) {
2055         ob_index++;
2056       }
2057
2058       if (duplicates[i] == -1) {
2059         continue;
2060       }
2061
2062       copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv);
2063       changed[ob_index] = true;
2064     }
2065
2066     for (ob_index = 0; ob_index < objects_len; ob_index++) {
2067       if (changed[ob_index]) {
2068         Object *obedit = objects[ob_index];
2069         uvedit_live_unwrap_update(sima, scene, obedit);
2070         DEG_id_tag_update(obedit->data, 0);
2071         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2072       }
2073     }
2074   }
2075
2076   BLI_kdtree_2d_free(tree);
2077   BLI_array_free(mloopuv_arr);
2078   BLI_array_free(duplicates);
2079   MEM_freeN(changed);
2080   MEM_freeN(objects);
2081   MEM_freeN(ob_mloopuv_max_idx);
2082
2083   return OPERATOR_FINISHED;
2084 }
2085
2086 static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
2087 {
2088   Scene *scene = CTX_data_scene(C);
2089   ViewLayer *view_layer = CTX_data_view_layer(C);
2090   SpaceImage *sima = CTX_wm_space_image(C);
2091   Image *ima = CTX_data_edit_image(C);
2092   ToolSettings *ts = scene->toolsettings;
2093
2094   const float threshold = RNA_float_get(op->ptr, "threshold");
2095   const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
2096
2097   uint objects_len = 0;
2098   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
2099       view_layer, ((View3D *)NULL), &objects_len);
2100
2101   /* Calculate max possible number of kdtree nodes. */
2102   int uv_maxlen = 0;
2103   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2104     Object *obedit = objects[ob_index];
2105     BMEditMesh *em = BKE_editmesh_from_object(obedit);
2106     uv_maxlen += em->bm->totloop;
2107   }
2108
2109   KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
2110
2111   MLoopUV **mloopuv_arr = NULL;
2112   BLI_array_declare(mloopuv_arr);
2113
2114   int mloopuv_count = 0;
2115
2116   /* Add visible non-selected uvs to tree */
2117   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2118     BMIter iter, liter;
2119     BMFace *efa;
2120     BMLoop *l;
2121     Object *obedit = objects[ob_index];
2122     BMEditMesh *em = BKE_editmesh_from_object(obedit);
2123
2124     if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) {
2125       continue;
2126     }
2127
2128     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2129
2130     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2131       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
2132         continue;
2133       }
2134
2135       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2136         if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
2137           MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2138           BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
2139           BLI_array_append(mloopuv_arr, luv);
2140           mloopuv_count++;
2141         }
2142       }
2143     }
2144   }
2145
2146   BLI_kdtree_2d_balance(tree);
2147
2148   /* For each selected uv, find duplicate non selected uv. */
2149   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2150     BMIter iter, liter;
2151     BMFace *efa;
2152     BMLoop *l;
2153     bool changed = false;
2154     Object *obedit = objects[ob_index];
2155     BMEditMesh *em = BKE_editmesh_from_object(obedit);
2156
2157     if (synced_selection && (em->bm->totvertsel == 0)) {
2158       continue;
2159     }
2160
2161     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2162
2163     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2164       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
2165         continue;
2166       }
2167
2168       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2169         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
2170           MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2171           KDTreeNearest_2d nearest;
2172           const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest);
2173
2174           if (i != -1 && nearest.dist < threshold) {
2175             copy_v2_v2(luv->uv, mloopuv_arr[i]->uv);
2176             changed = true;
2177           }
2178         }
2179       }
2180     }
2181
2182     if (changed) {
2183       uvedit_live_unwrap_update(sima, scene, obedit);
2184       DEG_id_tag_update(obedit->data, 0);
2185       WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2186     }
2187   }
2188
2189   BLI_kdtree_2d_free(tree);
2190   BLI_array_free(mloopuv_arr);
2191   MEM_freeN(objects);
2192
2193   return OPERATOR_FINISHED;
2194 }
2195
2196 static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
2197 {
2198   if (RNA_boolean_get(op->ptr, "use_unselected")) {
2199     return uv_remove_doubles_to_unselected(C, op);
2200   }
2201   else {
2202     return uv_remove_doubles_to_selected(C, op);
2203   }
2204 }
2205
2206 static void UV_OT_remove_doubles(wmOperatorType *ot)
2207 {
2208   /* identifiers */
2209   ot->name = "Merge UVs by Distance";
2210   ot->description =
2211       "Selected UV vertices that are within a radius of each other are welded together";
2212   ot->idname = "UV_OT_remove_doubles";
2213   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2214
2215   /* api callbacks */
2216   ot->exec = uv_remove_doubles_exec;
2217   ot->poll = ED_operator_uvedit;
2218
2219   RNA_def_float(ot->srna,
2220                 "threshold",
2221                 0.02f,
2222                 0.0f,
2223                 10.0f,
2224                 "Merge Distance",
2225                 "Maximum distance between welded vertices",
2226                 0.0f,
2227                 1.0f);
2228   RNA_def_boolean(
2229       ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
2230 }
2231
2232 /** \} */
2233
2234 /* -------------------------------------------------------------------- */
2235 /** \name Weld Near Operator
2236  * \{ */
2237
2238 static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op))
2239 {
2240   uv_weld_align(C, UV_WELD);
2241
2242   return OPERATOR_FINISHED;
2243 }
2244
2245 static void UV_OT_weld(wmOperatorType *ot)
2246 {
2247   /* identifiers */
2248   ot->name = "Weld";
2249   ot->description = "Weld selected UV vertices together";
2250   ot->idname = "UV_OT_weld";
2251   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2252
2253   /* api callbacks */
2254   ot->exec = uv_weld_exec;
2255   ot->poll = ED_operator_uvedit;
2256 }
2257
2258 /** \} */
2259
2260 /* -------------------------------------------------------------------- */
2261 /** \name (De)Select All Operator
2262  * \{ */
2263
2264 static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
2265 {
2266   ToolSettings *ts = scene->toolsettings;
2267   BMEditMesh *em = BKE_editmesh_from_object(obedit);
2268   BMFace *efa;
2269   BMLoop *l;
2270   BMIter iter, liter;
2271   MLoopUV *luv;
2272
2273   if (ts->uv_flag & UV_SYNC_SELECTION) {
2274     return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
2275   }
2276   else {
2277     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2278     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2279       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
2280         continue;
2281       }
2282       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2283         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2284         if (luv->flag & MLOOPUV_VERTSEL) {
2285           return true;
2286         }
2287       }
2288     }
2289   }
2290   return false;
2291 }
2292
2293 static bool uv_select_is_any_selected_multi(Scene *scene,
2294                                             Image *ima,
2295                                             Object **objects,
2296                                             const uint objects_len)
2297 {
2298   bool found = false;
2299   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2300     Object *obedit = objects[ob_index];
2301     if (uv_select_is_any_selected(scene, ima, obedit)) {
2302       found = true;
2303       break;
2304     }
2305   }
2306   return found;
2307 }
2308
2309 static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
2310 {
2311   ToolSettings *ts = scene->toolsettings;
2312   BMEditMesh *em = BKE_editmesh_from_object(obedit);
2313   BMFace *efa;
2314   BMLoop *l;
2315   BMIter iter, liter;
2316   MLoopUV *luv;
2317
2318   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2319
2320   if (action == SEL_TOGGLE) {
2321     action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
2322   }
2323
2324   if (ts->uv_flag & UV_SYNC_SELECTION) {
2325     switch (action) {
2326       case SEL_TOGGLE:
2327         EDBM_select_toggle_all(em);
2328         break;
2329       case SEL_SELECT:
2330         EDBM_flag_enable_all(em, BM_ELEM_SELECT);
2331         break;
2332       case SEL_DESELECT:
2333         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
2334         break;
2335       case SEL_INVERT:
2336         EDBM_select_swap(em);
2337         EDBM_selectmode_flush(em);
2338         break;
2339     }
2340   }
2341   else {
2342     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2343       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
2344         continue;
2345       }
2346
2347       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2348         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2349
2350         switch (action) {
2351           case SEL_SELECT:
2352             luv->flag |= MLOOPUV_VERTSEL;
2353             break;
2354           case SEL_DESELECT:
2355             luv->flag &= ~MLOOPUV_VERTSEL;
2356             break;
2357           case SEL_INVERT:
2358             luv->flag ^= MLOOPUV_VERTSEL;
2359             break;
2360         }
2361       }
2362     }
2363   }
2364 }
2365
2366 static void uv_select_all_perform_multi(
2367     Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
2368 {
2369   if (action == SEL_TOGGLE) {
2370     action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT :
2371                                                                                  SEL_SELECT;
2372   }
2373
2374   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2375     Object *obedit = objects[ob_index];
2376     uv_select_all_perform(scene, ima, obedit, action);
2377   }
2378 }
2379
2380 static int uv_select_all_exec(bContext *C, wmOperator *op)
2381 {
2382   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
2383   Scene *scene = CTX_data_scene(C);
2384   ToolSettings *ts = scene->toolsettings;
2385   Image *ima = CTX_data_edit_image(C);
2386   ViewLayer *view_layer = CTX_data_view_layer(C);
2387
2388   int action = RNA_enum_get(op->ptr, "action");
2389
2390   uint objects_len = 0;
2391   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
2392       view_layer, ((View3D *)NULL), &objects_len);
2393
2394   uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
2395
2396   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2397     Object *obedit = objects[ob_index];
2398     uv_select_tag_update_for_object(depsgraph, ts, obedit);
2399   }
2400
2401   MEM_freeN(objects);
2402
2403   return OPERATOR_FINISHED;
2404 }
2405
2406 static void UV_OT_select_all(wmOperatorType *ot)
2407 {
2408   /* identifiers */
2409   ot->name = "(De)select All";
2410   ot->description = "Change selection of all UV vertices";
2411   ot->idname = "UV_OT_select_all";
2412   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2413
2414   /* api callbacks */
2415   ot->exec = uv_select_all_exec;
2416   ot->poll = ED_operator_uvedit;
2417
2418   WM_operator_properties_select_all(ot);
2419 }
2420
2421 /** \} */
2422
2423 /* -------------------------------------------------------------------- */
2424 /** \name Mouse Select Operator
2425  * \{ */
2426
2427 static bool uv_sticky_select(
2428     float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
2429 {
2430   int i;
2431
2432   /* this function test if some vertex needs to selected
2433    * in addition to the existing ones due to sticky select */
2434   if (sticky == SI_STICKY_DISABLE) {
2435     return false;
2436   }
2437
2438   for (i = 0; i < hitlen; i++) {
2439     if (hitv[i] == v) {
2440       if (sticky == SI_STICKY_LOC) {
2441         if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) {
2442           return true;
2443         }
2444       }
2445       else if (sticky == SI_STICKY_VERTEX) {
2446         return true;
2447       }
2448     }
2449   }
2450
2451   return false;
2452 }
2453
2454 static int uv_mouse_select_multi(bContext *C,
2455                                  Object **objects,
2456                                  uint objects_len,
2457                                  const float co[2],
2458                                  const bool extend,
2459                                  const bool deselect_all,
2460                                  const bool loop)
2461 {
2462   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
2463   SpaceImage *sima = CTX_wm_space_image(C);
2464   Scene *scene = CTX_data_scene(C);
2465   ToolSettings *ts = scene->toolsettings;
2466   Image *ima = CTX_data_edit_image(C);
2467   BMFace *efa;
2468   BMLoop *l;
2469   BMIter iter, liter;
2470   MLoopUV *luv;
2471   UvNearestHit hit = UV_NEAREST_HIT_INIT;
2472   int i, selectmode, sticky, sync, *hitv = NULL;
2473   bool select = true;
2474   bool found_item = false;
2475   /* 0 == don't flush, 1 == sel, -1 == desel;  only use when selection sync is enabled */
2476   int flush = 0;
2477   int hitlen = 0;
2478   float limit[2], **hituv = NULL;
2479
2480   /* notice 'limit' is the same no matter the zoom level, since this is like
2481    * remove doubles and could annoying if it joined points when zoomed out.
2482    * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
2483    * shift-selecting can consider an adjacent point close enough to add to
2484    * the selection rather than de-selecting the closest. */
2485
2486   float penalty_dist;
2487   {
2488     float penalty[2];
2489     uvedit_pixel_to_float(sima, limit, 0.05f);
2490     uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
2491     penalty_dist = len_v2(penalty);
2492   }
2493
2494   /* retrieve operation mode */
2495   if (ts->uv_flag & UV_SYNC_SELECTION) {
2496     sync = 1;
2497
2498     if (ts->selectmode & SCE_SELECT_FACE) {
2499       selectmode = UV_SELECT_FACE;
2500     }
2501     else if (ts->selectmode & SCE_SELECT_EDGE) {
2502       selectmode = UV_SELECT_EDGE;
2503     }
2504     else {
2505       selectmode = UV_SELECT_VERTEX;
2506     }
2507
2508     sticky = SI_STICKY_DISABLE;
2509   }
2510   else {
2511     sync = 0;
2512     selectmode = ts->uv_selectmode;
2513     sticky = (sima) ? sima->sticky : 1;
2514   }
2515
2516   /* find nearest element */
2517   if (loop) {
2518     /* find edge */
2519     found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
2520   }
2521   else if (selectmode == UV_SELECT_VERTEX) {
2522     /* find vertex */
2523     found_item = uv_find_nearest_vert_multi(
2524         scene, ima, objects, objects_len, co, penalty_dist, &hit);
2525     found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
2526
2527     if (found_item) {
2528       /* mark 1 vertex as being hit */
2529       hitv = BLI_array_alloca(hitv, hit.efa->len);
2530       hituv = BLI_array_alloca(hituv, hit.efa->len);
2531       copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
2532
2533       hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
2534       hituv[hit.lindex] = hit.luv->uv;
2535
2536       hitlen = hit.efa->len;
2537     }
2538   }
2539   else if (selectmode == UV_SELECT_EDGE) {
2540     /* find edge */
2541     found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
2542     found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
2543
2544     if (found_item) {
2545       /* mark 2 edge vertices as being hit */
2546       hitv = BLI_array_alloca(hitv, hit.efa->len);
2547       hituv = BLI_array_alloca(hituv, hit.efa->len);
2548       copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
2549
2550       hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
2551       hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
2552       hituv[hit.lindex] = hit.luv->uv;
2553       hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
2554
2555       hitlen = hit.efa->len;
2556     }
2557   }
2558   else if (selectmode == UV_SELECT_FACE) {
2559     /* find face */
2560     found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit);
2561     found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
2562
2563     if (found_item) {
2564       BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
2565       const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2566
2567       /* make active */
2568       BM_mesh_active_face_set(em->bm, hit.efa);
2569
2570       /* mark all face vertices as being hit */
2571
2572       hitv = BLI_array_alloca(hitv, hit.efa->len);
2573       hituv = BLI_array_alloca(hituv, hit.efa->len);
2574       BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) {
2575         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2576         hituv[i] = luv->uv;
2577         hitv[i] = BM_elem_index_get(l->v);
2578       }
2579
2580       hitlen = hit.efa->len;
2581     }
2582   }
2583   else if (selectmode == UV_SELECT_ISLAND) {
2584     found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
2585     found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
2586   }
2587
2588   if (!found_item) {
2589     if (deselect_all) {
2590       uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
2591
2592       for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2593         Object *obedit = objects[ob_index];
2594         uv_select_tag_update_for_object(depsgraph, ts, obedit);
2595       }
2596
2597       return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
2598     }
2599     return OPERATOR_CANCELLED;
2600   }
2601
2602   Object *obedit = hit.ob;
2603   BMEditMesh *em = BKE_editmesh_from_object(obedit);
2604   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2605
2606   /* do selection */
2607   if (loop) {
2608     if (!extend) {
2609       /* TODO(MULTI_EDIT): We only need to de-select non-active */
2610       uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
2611     }
2612     flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
2613   }
2614   else if (selectmode == UV_SELECT_ISLAND) {
2615     if (!extend) {
2616       /* TODO(MULTI_EDIT): We only need to de-select non-active */
2617       uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
2618     }
2619     /* Current behavior of 'extend'
2620      * is actually toggling, so pass extend flag as 'toggle' here */
2621     uv_select_linked_multi(
2622         scene, ima, objects, objects_len, limit, &hit, false, false, extend, false);
2623   }
2624   else if (extend) {
2625     if (selectmode == UV_SELECT_VERTEX) {
2626       /* (de)select uv vertex */
2627       select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
2628       uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
2629       flush = 1;
2630     }
2631     else if (selectmode == UV_SELECT_EDGE) {
2632       /* (de)select edge */
2633       select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
2634       uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
2635       flush = 1;
2636     }
2637     else if (selectmode == UV_SELECT_FACE) {
2638       /* (de)select face */
2639       select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
2640       uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
2641       flush = -1;
2642     }
2643
2644     /* de-selecting an edge may deselect a face too - validate */
2645     if (sync) {
2646       if (select == false) {
2647         BM_select_history_validate(em->bm);
2648       }
2649     }
2650
2651     /* (de)select sticky uv nodes */
2652     if (sticky != SI_STICKY_DISABLE) {
2653
2654       BM_mesh_elem_index_ensure(em->bm, BM_VERT);
2655
2656       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2657         if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
2658           continue;
2659         }
2660
2661         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2662           luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2663           if (uv_sticky_select(
2664                   limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
2665             uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
2666           }
2667         }
2668       }
2669
2670       flush = select ? 1 : -1;
2671     }
2672   }
2673   else {
2674     /* deselect all */
2675     uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
2676
2677     if (selectmode == UV_SELECT_VERTEX) {
2678       /* select vertex */
2679       uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
2680       flush = 1;
2681     }
2682     else if (selectmode == UV_SELECT_EDGE) {
2683       /* select edge */
2684       uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
2685       flush = 1;
2686     }
2687     else if (selectmode == UV_SELECT_FACE) {
2688       /* select face */
2689       uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
2690     }
2691
2692     /* select sticky uvs */
2693     if (sticky != SI_STICKY_DISABLE) {
2694       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2695         if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
2696           continue;
2697         }
2698
2699         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2700           if (sticky == SI_STICKY_DISABLE) {
2701             continue;
2702           }
2703           luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2704
2705           if (uv_sticky_select(
2706                   limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
2707             uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
2708           }
2709
2710           flush = 1;
2711         }
2712       }
2713     }
2714   }
2715
2716   if (sync) {
2717     /* flush for mesh selection */
2718
2719     /* before bmesh */
2720 #if 0
2721     if (ts->selectmode != SCE_SELECT_FACE) {
2722       if (flush == 1) {
2723         EDBM_select_flush(em);
2724       }
2725       else if (flush == -1) {
2726         EDBM_deselect_flush(em);
2727       }
2728     }
2729 #else
2730     if (flush != 0) {
2731       if (loop) {
2732         /* push vertex -> edge selection */
2733         if (select) {
2734           EDBM_select_flush(em);
2735         }
2736         else {
2737           EDBM_deselect_flush(em);
2738         }
2739       }
2740       else {
2741         EDBM_selectmode_flush(em);
2742       }
2743     }
2744 #endif
2745   }
2746
2747   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2748     Object *obiter = objects[ob_index];
2749     uv_select_tag_update_for_object(depsgraph, ts, obiter);
2750   }
2751
2752   return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
2753 }
2754 static int uv_mouse_select(
2755     bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop)
2756 {
2757   ViewLayer *view_layer = CTX_data_view_layer(C);
2758   uint objects_len = 0;
2759   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
2760       view_layer, ((View3D *)NULL), &objects_len);
2761   int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop);
2762   MEM_freeN(objects);
2763   return ret;
2764 }
2765
2766 static int uv_select_exec(bContext *C, wmOperator *op)
2767 {
2768   float co[2];
2769
2770   RNA_float_get_array(op->ptr, "location", co);
2771   const bool extend = RNA_boolean_get(op->ptr, "extend");
2772   const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
2773   const bool loop = false;
2774
2775   return uv_mouse_select(C, co, extend, deselect_all, loop);
2776 }
2777
2778 static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2779 {
2780   ARegion *ar = CTX_wm_region(C);
2781   float co[2];
2782
2783   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2784   RNA_float_set_array(op->ptr, "location", co);
2785
2786   return uv_select_exec(C, op);
2787 }
2788
2789 static void UV_OT_select(wmOperatorType *ot)
2790 {
2791   /* identifiers */
2792   ot->name = "Select";
2793   ot->description = "Select UV vertices";
2794   ot->idname = "UV_OT_select";
2795   ot->flag = OPTYPE_UNDO;
2796
2797   /* api callbacks */
2798   ot->exec = uv_select_exec;
2799   ot->invoke = uv_select_invoke;
2800   ot->poll = ED_operator_uvedit; /* requires space image */
2801
2802   /* properties */
2803   PropertyRNA *prop;
2804   RNA_def_boolean(ot->srna,
2805                   "extend",
2806                   0,
2807                   "Extend",
2808                   "Extend selection rather than clearing the existing selection");
2809   prop = RNA_def_boolean(ot->srna,
2810                          "deselect_all",
2811                          false,
2812                          "Deselect On Nothing",
2813                          "Deselect all when nothing under the cursor");
2814   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2815
2816   RNA_def_float_vector(
2817       ot->srna,
2818       "location",
2819       2,
2820       NULL,
2821       -FLT_MAX,
2822       FLT_MAX,
2823       "Location",
2824       "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
2825       -100.0f,
2826       100.0f);
2827 }
2828
2829 /** \} */
2830
2831 /* -------------------------------------------------------------------- */
2832 /** \name Loop Select Operator
2833  * \{ */
2834
2835 static int uv_select_loop_exec(bContext *C, wmOperator *op)
2836 {
2837   float co[2];
2838
2839   RNA_float_get_array(op->ptr, "location", co);
2840   const bool extend = RNA_boolean_get(op->ptr, "extend");
2841   const bool deselect_all = false;
2842   const bool loop = true;
2843
2844   return uv_mouse_select(C, co, extend, deselect_all, loop);
2845 }
2846
2847 static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2848 {
2849   ARegion *ar = CTX_wm_region(C);
2850   float co[2];
2851
2852   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2853   RNA_float_set_array(op->ptr, "location", co);
2854
2855   return uv_select_loop_exec(C, op);
2856 }
2857
2858 static void UV_OT_select_loop(wmOperatorType *ot)
2859 {
2860   /* identifiers */
2861   ot->name = "Loop Select";
2862   ot->description = "Select a loop of connected UV vertices";
2863   ot->idname = "UV_OT_select_loop";
2864   ot->flag = OPTYPE_UNDO;
2865
2866   /* api callbacks */
2867   ot->exec = uv_select_loop_exec;
2868   ot->invoke = uv_select_loop_invoke;
2869   ot->poll = ED_operator_uvedit; /* requires space image */
2870
2871   /* properties */
2872   RNA_def_boolean(ot->srna,
2873                   "extend",
2874                   0,
2875                   "Extend",
2876                   "Extend selection rather than clearing the existing selection");
2877   RNA_def_float_vector(
2878       ot->srna,
2879       "location",
2880       2,
2881       NULL,
2882       -FLT_MAX,
2883       FLT_MAX,
2884       "Location",
2885       "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
2886       -100.0f,
2887       100.0f);
2888 }
2889
2890 /** \} */
2891
2892 /* -------------------------------------------------------------------- */
2893 /** \name Select Linked Operator
2894  * \{ */
2895
2896 static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
2897 {
2898   SpaceImage *sima = CTX_wm_space_image(C);
2899   Scene *scene = CTX_data_scene(C);
2900   ToolSettings *ts = scene->toolsettings;
2901   ViewLayer *view_layer = CTX_data_view_layer(C);
2902   Image *ima = CTX_data_edit_image(C);
2903   float limit[2];
2904   bool extend = true;
2905   bool deselect = false;
2906   bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
2907
2908   UvNearestHit hit = UV_NEAREST_HIT_INIT;
2909
2910   if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
2911     BKE_report(op->reports,
2912                RPT_ERROR,
2913                "Select linked only works in face select mode when sync selection is enabled");
2914     return OPERATOR_CANCELLED;
2915   }
2916
2917   if (pick) {
2918     extend = RNA_boolean_get(op->ptr, "extend");
2919     deselect = RNA_boolean_get(op->ptr, "deselect");
2920   }
2921   uvedit_pixel_to_float(sima, limit, 0.05f);
2922
2923   uint objects_len = 0;
2924   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
2925       view_layer, ((View3D *)NULL), &objects_len);
2926
2927   if (pick) {
2928     float co[2];
2929
2930     if (event) {
2931       /* invoke */
2932       ARegion *ar = CTX_wm_region(C);
2933
2934       UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2935       RNA_float_set_array(op->ptr, "location", co);
2936     }
2937     else {
2938       /* exec */
2939       RNA_float_get_array(op->ptr, "location", co);
2940     }
2941
2942     if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
2943       MEM_freeN(objects);
2944       return OPERATOR_CANCELLED;
2945     }
2946   }
2947
2948   if (!extend) {
2949     uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
2950   }
2951
2952   uv_select_linked_multi(scene,
2953                          ima,
2954                          objects,
2955                          objects_len,
2956                          limit,
2957                          pick ? &hit : NULL,
2958                          extend,
2959                          deselect,
2960                          false,
2961                          select_faces);
2962
2963   /* weak!, but works */
2964   Object **objects_free = objects;
2965   if (pick) {
2966     objects = &hit.ob;
2967     objects_len = 1;
2968   }
2969
2970   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2971     Object *obedit = objects[ob_index];
2972     DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
2973     WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2974   }
2975
2976   MEM_SAFE_FREE(objects_free);
2977
2978   return OPERATOR_FINISHED;
2979 }
2980
2981 static int uv_select_linked_exec(bContext *C, wmOperator *op)
2982 {
2983   return uv_select_linked_internal(C, op, NULL, false);
2984 }
2985
2986 static void UV_OT_select_linked(wmOperatorType *ot)
2987 {
2988   /* identifiers */
2989   ot->name = "Select Linked";
2990   ot->description = "Select all UV vertices linked to the active UV map";
2991   ot->idname = "UV_OT_select_linked";
2992   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2993
2994   /* api callbacks */
2995   ot->exec = uv_select_linked_exec;
2996   ot->poll = ED_operator_uvedit; /* requires space image */
2997
2998   /* flags */
2999   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3000 }
3001
3002 /** \} */
3003
3004 /* -------------------------------------------------------------------- */
3005 /** \name Select Linked (Cursor Pick) Operator
3006  * \{ */
3007
3008 static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3009 {
3010   return uv_select_linked_internal(C, op, event, true);
3011 }
3012
3013 static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
3014 {
3015   return uv_select_linked_internal(C, op, NULL, true);
3016 }
3017
3018 static void UV_OT_select_linked_pick(wmOperatorType *ot)
3019 {
3020   /* identifiers */
3021   ot->name = "Select Linked Pick";
3022   ot->description = "Select all UV vertices linked under the mouse";
3023   ot->idname = "UV_OT_select_linked_pick";
3024
3025   /* flags */
3026   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3027
3028   /* api callbacks */
3029   ot->invoke = uv_select_linked_pick_invoke;
3030   ot->exec = uv_select_linked_pick_exec;
3031   ot->poll = ED_operator_uvedit; /* requires space image */
3032
3033   /* properties */
3034   RNA_def_boolean(ot->srna,
3035                   "extend",
3036                   0,
3037                   "Extend",
3038                   "Extend selection rather than clearing the existing selection");
3039   RNA_def_boolean(ot->srna,
3040                   "deselect",
3041                   0,
3042                   "Deselect",
3043                   "Deselect linked UV vertices rather than selecting them");
3044   RNA_def_float_vector(
3045       ot->srna,
3046       "location",
3047       2,
3048       NULL,
3049       -FLT_MAX,
3050       FLT_MAX,
3051       "Location",
3052       "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
3053       -100.0f,
3054       100.0f);
3055 }
3056
3057 /** \} */
3058
3059 /* -------------------------------------------------------------------- */
3060 /** \name Select Split Operator
3061  * \{ */
3062
3063 /**
3064  * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect
3065  * but in this case they are not joined to begin with (only having the behavior of being joined)
3066  * so its best to call this #uv_select_split() instead of just split(), but assigned to the same
3067  * key as #MESH_OT_split - Campbell.
3068  */
3069 static int uv_select_split_exec(bContext *C, wmOperator *op)
3070 {
3071   Scene *scene = CTX_data_scene(C);
3072   ViewLayer *view_layer = CTX_data_view_layer(C);
3073   ToolSettings *ts = scene->toolsettings;
3074   Image *ima = CTX_data_edit_image(C);
3075
3076   BMFace *efa;
3077   BMLoop *l;
3078   BMIter iter, liter;
3079   MLoopUV *luv;
3080
3081   if (ts->uv_flag & UV_SYNC_SELECTION) {
3082     BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
3083     return OPERATOR_CANCELLED;
3084   }
3085
3086   bool changed_multi = false;
3087
3088   uint objects_len = 0;
3089   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
3090       view_layer, ((View3D *)NULL), &objects_len);
3091
3092   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3093     Object *obedit = objects[ob_index];
3094     BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
3095
3096     bool changed = false;
3097
3098     const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
3099
3100     BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
3101       bool is_sel = false;
3102       bool is_unsel = false;
3103
3104       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
3105         continue;
3106       }
3107
3108       /* are we all selected? */
3109       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3110         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3111
3112         if (luv->flag & MLOOPUV_VERTSEL) {
3113           is_sel = true;
3114         }
3115         else {
3116           is_unsel = true;
3117         }
3118
3119         /* we have mixed selection, bail out */
3120         if (is_sel && is_unsel) {
3121           break;
3122         }
3123       }
3124
3125       if (is_sel && is_unsel) {
3126         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3127           luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3128           luv->flag &= ~MLOOPUV_VERTSEL;
3129         }
3130
3131         changed = true;
3132       }
3133     }
3134
3135     if (changed) {
3136       changed_multi = true;
3137       WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
3138     }
3139   }
3140   MEM_freeN(objects);
3141
3142   return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3143 }
3144
3145 static void UV_OT_select_split(wmOperatorType *ot)
3146 {
3147   /* identifiers */
3148   ot->name = "Select Split";
3149   ot->description = "Select only entirely selected faces";
3150   ot->idname = "UV_OT_select_split";
3151   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3152
3153   /* api callbacks */
3154   ot->exec = uv_select_split_exec;
3155   ot->poll = ED_operator_uvedit; /* requires space image */
3156 }
3157
3158 static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short select)
3159 {
3160   /* bmesh API handles flushing but not on de-select */
3161   if (ts->uv_flag & UV_SYNC_SELECTION) {
3162     if (ts->selectmode != SCE_SELECT_FACE) {
3163       if (select == false) {
3164         EDBM_deselect_flush(em);
3165       }
3166       else {
3167         EDBM_select_flush(em);
3168       }
3169     }
3170
3171     if (select == false) {
3172       BM_select_history_validate(em->bm);
3173     }
3174   }
3175 }
3176
3177 static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
3178                                             const ToolSettings *ts,
3179                                             Object *obedit)
3180 {
3181   if (ts->uv_flag & UV_SYNC_SELECTION) {
3182     DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
3183     WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
3184   }
3185   else {
3186     Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
3187     BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
3188     /* Only for region redraw. */
3189     WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
3190   }
3191 }
3192
3193 /** \} */
3194
3195 /* -------------------------------------------------------------------- */
3196 /** \name Select/Tag Flushing Utils
3197  *
3198  * Utility functions to flush the uv-selection from tags.
3199  * \{ */
3200
3201 /**
3202  * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
3203  */
3204 static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene,
3205                                                          BMEditMesh *em,
3206                                                          UvVertMap *vmap,
3207                                                          const unsigned int efa_index,
3208                                                          BMLoop *l,
3209                                                          const bool select,
3210                                                          const int cd_loop_uv_offset)
3211 {
3212   UvMapVert *start_vlist = NULL, *vlist_iter;
3213   BMFace *efa_vlist;
3214
3215   uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
3216
3217   vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
3218
3219   while (vlist_iter) {
3220     if (vlist_iter->separate) {
3221       start_vlist = vlist_iter;
3222     }
3223
3224     if (efa_index == vlist_iter->poly_index) {
3225       break;
3226     }
3227
3228     vlist_iter = vlist_iter->next;
3229   }
3230
3231   vlist_iter = start_vlist;
3232   while (vlist_iter) {
3233
3234     if (vlist_iter != start_vlist && vlist_iter->separate) {
3235       break;
3236     }
3237
3238     if (efa_index != vlist_iter->poly_index) {
3239       BMLoop *l_other;
3240       efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
3241       /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
3242
3243       l_other = BM_iter_at_index(
3244           em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
3245
3246       uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
3247     }
3248     vlist_iter = vlist_iter->next;
3249   }
3250 }
3251
3252 /**
3253  * Flush the selection from face tags based on sticky and selection modes.
3254  *
3255  * needed because settings the selection a face is done in a number of places but it also
3256  * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes
3257  * is best done in a separate function.
3258  *
3259  * \note This function is very similar to #uv_select_flush_from_tag_loop,
3260  * be sure to update both upon changing.
3261  */
3262 static void uv_select_flush_from_tag_face(SpaceImage *sima,
3263                                           Scene *scene,
3264                                           Object *obedit,
3265                                           const bool select)
3266 {
3267   /* Selecting UV Faces with some modes requires us to change
3268    * the selection in other faces (depending on the sticky mode).
3269    *
3270    * This only needs to be done when the Mesh is not used for
3271    * selection (so for sticky modes, vertex or location based). */
3272
3273   ToolSettings *ts = scene->toolsettings;
3274   BMEditMesh *em = BKE_editmesh_from_object(obedit);
3275   BMFace *efa;
3276   BMLoop *l;
3277   BMIter iter, liter;
3278   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3279
3280   if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
3281     /* Tag all verts as untouched, then touch the ones that have a face center
3282      * in the loop and select all MLoopUV's that use a touched vert. */
3283     BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
3284
3285     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3286       if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
3287         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3288           BM_elem_flag_enable(l->v, BM_ELEM_TAG);
3289         }
3290       }
3291     }
3292
3293     /* now select tagged verts */
3294     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3295       /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
3296
3297       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3298         if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
3299           uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
3300         }
3301       }
3302     }
3303   }
3304   else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
3305     struct UvVertMap *vmap;
3306     float limit[2];
3307     unsigned int efa_index;
3308
3309     uvedit_pixel_to_float(sima, limit, 0.05);
3310
3311     BM_mesh_elem_table_ensure(em->bm, BM_FACE);
3312     vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
3313     if (vmap == NULL) {
3314       return;
3315     }
3316
3317     BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
3318       if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
3319         /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
3320
3321         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3322           uv_select_flush_from_tag_sticky_loc_internal(
3323               scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
3324         }
3325       }
3326     }
3327     BM_uv_vert_map_free(vmap);
3328   }
3329   else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
3330     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3331       if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
3332         uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
3333       }
3334     }
3335   }
3336 }
3337
3338 /**
3339  * Flush the selection from loop tags based on sticky and selection modes.
3340  *
3341  * needed because settings the selection a face is done in a number of places but it also needs
3342  * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done
3343  * in a separate function.
3344  *
3345  * \note This function is very similar to #uv_select_flush_from_tag_loop,
3346  * be sure to update both upon changing.
3347  */
3348 static void uv_select_flush_from_tag_loop(SpaceImage *sima,
3349                                           Scene *scene,
3350                                           Object *obedit,
3351                                           const bool select)
3352 {
3353   /* Selecting UV Loops with some modes requires us to change
3354    * the selection in other faces (depending on the sticky mode).
3355    *
3356    * This only needs to be done when the Mesh is not used for
3357    * selection (so for sticky modes, vertex or location based). */
3358
3359   ToolSettings *ts = scene->toolsettings;
3360   BMEditMesh *em = BKE_editmesh_from_object(obedit);
3361   BMFace *efa;
3362   BMLoop *l;
3363   BMIter iter, liter;
3364
3365   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3366
3367   if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
3368     /* Tag all verts as untouched, then touch the ones that have a face center
3369      * in the loop and select all MLoopUV's that use a touched vert. */
3370     BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
3371
3372     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3373       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3374         if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
3375           BM_elem_flag_enable(l->v, BM_ELEM_TAG);
3376         }
3377       }
3378     }
3379
3380     /* now select tagged verts */
3381     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3382       /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
3383
3384       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3385         if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
3386           uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
3387         }
3388       }
3389     }
3390   }
3391   else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
3392     struct UvVertMap *vmap;
3393     float limit[2];
3394     unsigned int efa_index;
3395
3396     uvedit_pixel_to_float(sima, limit, 0.05);
3397
3398     BM_mesh_elem_table_ensure(em->bm, BM_FACE);
3399     vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
3400     if (vmap == NULL) {
3401       return;
3402     }
3403
3404     BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
3405       /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
3406
3407       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3408         if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
3409           uv_select_flush_from_tag_sticky_loc_internal(
3410               scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
3411         }
3412       }
3413     }
3414     BM_uv_vert_map_free(vmap);
3415   }
3416   else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
3417     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3418       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3419         if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
3420           uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
3421         }
3422       }
3423     }
3424   }
3425 }
3426
3427 /** \} */
3428
3429 /* -------------------------------------------------------------------- */
3430 /** \name Box Select Operator
3431  * \{ */
3432
3433 static int uv_box_select_exec(bContext *C, wmOperator *op)
3434 {
3435   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
3436   SpaceImage *sima = CTX_wm_space_image(C);
3437   Scene *scene = CTX_data_scene(C);
3438   ToolSettings *ts = scene->toolsettings;
3439   ViewLayer *view_layer = CTX_data_view_layer(C);
3440   Image *ima = CTX_data_edit_image(C);
3441   ARegion *ar = CTX_wm_region(C);
3442   BMFace *efa;
3443   BMLoop *l;
3444   BMIter iter, liter;
3445   MLoopUV *luv;
3446   rctf rectf;
3447   bool pinned;
3448   const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3449                                     (ts->selectmode == SCE_SELECT_FACE) :
3450                                     (ts->uv_selectmode == UV_SELECT_FACE));
3451
3452   /* get rectangle from operator */
3453   WM_operator_properties_border_to_rctf(op, &rectf);
3454   UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
3455
3456   const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
3457   const bool select = (sel_op != SEL_OP_SUB);
3458
3459   pinned = RNA_boolean_get(op->ptr, "pinned");
3460
3461   bool changed_multi = false;
3462
3463   uint objects_len = 0;
3464   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
3465       view_layer, ((View3D *)NULL), &objects_len);
3466
3467   if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3468     uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
3469   }
3470
3471   /* don't indent to avoid diff noise! */
3472   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3473     Object *obedit = objects[ob_index];
3474     BMEditMesh *em = BKE_editmesh_from_object(obedit);
3475
3476     bool changed = false;
3477
3478     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3479
3480     /* do actual selection */
3481     if (use_face_center && !pinned) {
3482       /* handle face selection mode */
3483       float cent[2];
3484
3485       changed = false;
3486
3487       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3488         /* assume not touched */
3489         BM_elem_flag_disable(efa, BM_ELEM_TAG);
3490
3491         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
3492           uv_poly_center(efa, cent, cd_loop_uv_offset);
3493           if (BLI_rctf_isect_pt_v(&rectf, cent)) {
3494             BM_elem_flag_enable(efa, BM_ELEM_TAG);
3495             changed = true;
3496           }
3497         }
3498       }
3499
3500       /* (de)selects all tagged faces and deals with sticky modes */
3501       if (changed) {
3502         uv_select_flush_from_tag_face(sima, scene, obedit, select);
3503       }
3504     }
3505     else {
3506       /* other selection modes */
3507       changed = true;
3508       BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
3509
3510       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3511         if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
3512           continue;
3513         }
3514         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3515           luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3516
3517           if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
3518
3519             /* UV_SYNC_SELECTION - can't do pinned selection */
3520             if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
3521               uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
3522               BM_elem_flag_enable(l->v, BM_ELEM_TAG);
3523             }
3524           }
3525           else if (pinned) {
3526             if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
3527               uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
3528               BM_elem_flag_enable(l->v, BM_ELEM_TAG);
3529             }
3530           }
3531         }
3532       }
3533
3534       if (sima->sticky == SI_STICKY_VERTEX) {
3535         uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
3536       }
3537     }
3538
3539     if (changed) {
3540       changed_multi = true;
3541
3542       uv_select_sync_flush(ts, em, select);
3543       uv_select_tag_update_for_object(depsgraph, ts, obedit);
3544     }
3545   }
3546
3547   MEM_freeN(objects);
3548
3549   return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3550 }
3551
3552 static void UV_OT_select_box(wmOperatorType *ot)
3553 {
3554   /* identifiers */
3555   ot->name = "Box Select";
3556   ot->description = "Select UV vertices using box selection";
3557   ot->idname = "UV_OT_select_box";
3558
3559   /* api callbacks */
3560   ot->invoke = WM_gesture_box_invoke;
3561   ot->exec = uv_box_select_exec;
3562   ot->modal = WM_gesture_box_modal;
3563   ot->poll = ED_operator_uvedit_space_image; /* requires space image */
3564   ot->cancel = WM_gesture_box_cancel;
3565
3566   /* flags */
3567   ot->flag = OPTYPE_UNDO;
3568
3569   /* properties */
3570   RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
3571
3572   WM_operator_properties_gesture_box(ot);
3573   WM_operator_properties_select_operation_simple(ot);
3574 }
3575
3576 /** \} */
3577
3578 /* -------------------------------------------------------------------- */
3579 /** \name Circle Select Operator
3580  * \{ */
3581
3582 static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2])
3583 {
3584   /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
3585   float x, y;
3586   x = (uv[0] - offset[0]) * ellipse[0];
3587   y = (uv[1] - offset[1]) * ellipse[1];
3588   return ((x * x + y * y) < 1.0f);
3589 }
3590
3591 static int uv_circle_select_exec(bContext *C, wmOperator *op)
3592 {
3593   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
3594   SpaceImage *sima = CTX_wm_space_image(C);
3595   Image *ima = CTX_data_edit_image(C);
3596   Scene *scene = CTX_data_scene(C);
3597   ViewLayer *view_layer = CTX_data_view_layer(C);
3598   ToolSettings *ts = scene->toolsettings;
3599   ARegion *ar = CTX_wm_region(C);
3600   BMFace *efa;
3601   BMLoop *l;
3602   BMIter iter, liter;
3603   MLoopUV *luv;
3604   int x, y, radius, width, height;
3605   float zoomx, zoomy, offset[2], ellipse[2];
3606
3607   const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3608                                     (ts->selectmode == SCE_SELECT_FACE) :
3609                                     (ts->uv_selectmode == UV_SELECT_FACE));
3610
3611   /* get operator properties */
3612   x = RNA_int_get(op->ptr, "x");
3613   y = RNA_int_get(op->ptr, "y");
3614   radius = RNA_int_get(op->ptr, "radius");
3615
3616   /* compute ellipse size and location, not a circle since we deal
3617    * with non square image. ellipse is normalized, r = 1.0. */
3618   ED_space_image_get_size(sima, &width, &height);
3619   ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
3620
3621   ellipse[0] = width * zoomx / radius;
3622   ellipse[1] = height * zoomy / radius;
3623
3624   UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
3625
3626   bool changed_multi = false;
3627
3628   uint objects_len = 0;
3629   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
3630       view_layer, ((View3D *)NULL), &objects_len);
3631
3632   const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
3633                                               WM_gesture_is_modal_first(op->customdata));
3634   const bool select = (sel_op != SEL_OP_SUB);
3635   if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3636     uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
3637     changed_multi = true;
3638   }
3639
3640   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3641     Object *obedit = objects[ob_index];
3642     BMEditMesh *em = BKE_editmesh_from_object(obedit);
3643
3644     bool changed = false;
3645
3646     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3647
3648     /* do selection */
3649     if (use_face_center) {
3650       changed = false;
3651       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3652         BM_elem_flag_disable(efa, BM_ELEM_TAG);
3653         /* assume not touched */
3654         if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
3655           float cent[2];
3656           uv_poly_center(efa, cent, cd_loop_uv_offset);
3657           if (uv_inside_circle(cent, offset, ellipse)) {
3658             BM_elem_flag_enable(efa, BM_ELEM_TAG);
3659             changed = true;
3660           }
3661         }
3662       }
3663
3664       /* (de)selects all tagged faces and deals with sticky modes */
3665       if (changed) {
3666         uv_select_flush_from_tag_face(sima, scene, obedit, select);
3667       }
3668     }
3669     else {
3670       BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
3671
3672       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3673         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3674           luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3675           if (uv_inside_circle(luv->uv, offset, ellipse)) {
3676             changed = true;
3677             uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
3678             BM_elem_flag_enable(l->v, BM_ELEM_TAG);
3679           }
3680         }
3681       }
3682
3683       if (sima->sticky == SI_STICKY_VERTEX) {
3684         uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
3685       }
3686     }
3687
3688     if (changed) {
3689       changed_multi = true;
3690
3691       uv_select_sync_flush(ts, em, select);
3692       uv_select_tag_update_for_object(depsgraph, ts, obedit);
3693     }
3694   }
3695   MEM_freeN(objects);
3696
3697   return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3698 }
3699
3700 static void UV_OT_select_circle(wmOperatorType *ot)
3701 {
3702   /* identifiers */
3703   ot->name = "Circle Select";
3704   ot->description = "Select UV vertices using circle selection";
3705   ot->idname = "UV_OT_select_circle";
3706
3707   /* api callbacks */
3708   ot->invoke = WM_gesture_circle_invoke;
3709   ot->modal = WM_gesture_circle_modal;
3710   ot->exec = uv_circle_select_exec;
3711   ot->poll = ED_operator_uvedit_space_image; /* requires space image */
3712   ot->cancel = WM_gesture_circle_cancel;
3713
3714   /* flags */
3715   ot->flag = OPTYPE_UNDO;
3716
3717   /* properties */
3718   WM_operator_properties_gesture_circle(ot);
3719   WM_operator_properties_select_operation_simple(ot);
3720 }
3721
3722 /** \} */
3723
3724 /* -------------------------------------------------------------------- */
3725 /** \name Lasso Select Operator
3726  * \{ */
3727
3728 static bool do_lasso_select_mesh_uv(bContext *C,
3729                                     const int mcords[][2],
3730                                     short moves,
3731                                     const eSelectOp sel_op)
3732 {
3733   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
3734   SpaceImage *sima = CTX_wm_space_image(C);
3735   Image *ima = CTX_data_edit_image(C);
3736   ARegion *ar = CTX_wm_region(C);
3737   Scene *scene = CTX_data_scene(C);
3738   ToolSettings *ts = scene->toolsettings;
3739   ViewLayer *view_layer = CTX_data_view_layer(C);
3740   const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
3741                                     (ts->selectmode == SCE_SELECT_FACE) :
3742                                     (ts->uv_selectmode == UV_SELECT_FACE));
3743   const bool select = (sel_op != SEL_OP_SUB);
3744
3745   BMIter iter, liter;
3746
3747   BMFace *efa;
3748   BMLoop *l;
3749   int screen_uv[2];
3750   bool changed_multi = false;
3751   rcti rect;
3752
3753   BLI_lasso_boundbox(&rect, mcords, moves);
3754
3755   uint objects_len = 0;
3756   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
3757       view_layer, ((View3D *)NULL), &objects_len);
3758
3759   if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3760     uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
3761   }
3762
3763   /* don't indent to avoid diff noise! */
3764   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3765     Object *obedit = objects[ob_index];
3766
3767     bool changed = false;
3768
3769     BMEditMesh *em = BKE_editmesh_from_object(obedit);
3770
3771     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3772
3773     if (use_face_center) { /* Face Center Sel */
3774       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3775         BM_elem_flag_disable(efa, BM_ELEM_TAG);
3776         /* assume not touched */
3777         if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
3778           float cent[2];
3779           uv_poly_center(efa, cent, cd_loop_uv_offset);
3780
3781           if (UI_view2d_view_to_region_clip(
3782                   &ar->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) &&
3783               BLI_rcti_isect_pt_v(&rect, screen_uv) &&
3784               BLI_lasso_is_point_inside(
3785                   mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
3786             BM_elem_flag_enable(efa, BM_ELEM_TAG);
3787             changed = true;
3788           }
3789         }
3790       }
3791
3792       /* (de)selects all tagged faces and deals with sticky modes */
3793       if (changed) {
3794         uv_select_flush_from_tag_face(sima, scene, obedit, select);
3795       }
3796     }
3797     else { /* Vert Sel */
3798       BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
3799
3800       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3801         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
3802           BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3803             if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
3804               MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3805               if (UI_view2d_view_to_region_clip(
3806                       &ar->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) &&
3807                   BLI_rcti_isect_pt_v(&rect, screen_uv) &&
3808                   BLI_lasso_is_point_inside(
3809                       mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
3810                 uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
3811                 changed = true;
3812                 BM_elem_flag_enable(l->v, BM_ELEM_TAG);
3813               }
3814             }
3815           }
3816         }
3817       }
3818
3819       if (sima->sticky == SI_STICKY_VERTEX) {
3820         uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
3821       }
3822     }
3823
3824     if (changed) {
3825       changed_multi = true;
3826
3827       uv_select_sync_flush(ts, em, select);
3828       uv_select_tag_update_for_object(depsgraph, ts, obedit);
3829     }
3830   }
3831   MEM_freeN(objects);
3832
3833   return changed_multi;
3834 }
3835
3836 static int uv_lasso_select_exec(bContext *C, wmOperator *op)
3837 {
3838   int mcords_tot;
3839   const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
3840
3841   if (mcords) {
3842     const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
3843     bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op);
3844     MEM_freeN((void *)mcords);
3845
3846     return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3847   }
3848
3849   return OPERATOR_PASS_THROUGH;
3850 }
3851
3852 static void UV_OT_select_lasso(wmOperatorType *ot)
3853 {
3854   ot->name = "Lasso Select UV";
3855   ot->description = "Select UVs using lasso selection";
3856   ot->idname = "UV_OT_select_lasso";
3857
3858   ot->invoke = WM_gesture_lasso_invoke;
3859   ot->modal = WM_gesture_lasso_modal;
3860   ot->exec = uv_lasso_select_exec;
3861   ot->poll = ED_operator_uvedit_space_image;
3862   ot->cancel = WM_gesture_lasso_cancel;
3863
3864   /* flags */
3865   ot->flag = OPTYPE_UNDO;
3866
3867   /* properties */
3868   WM_operator_properties_gesture_lasso(ot);
3869   WM_operator_properties_select_operation_simple(ot);
3870 }
3871
3872 /** \} */
3873
3874 /* -------------------------------------------------------------------- */
3875 /** \name Snap Cursor Operator
3876  * \{ */
3877
3878 static void uv_snap_to_pixel(float uvco[2], float w, float h)
3879 {
3880   uvco[0] = roundf(uvco[0] * w) / w;
3881   uvco[1] = roundf(uvco[1] * h) / h;
3882 }
3883
3884 static void uv_snap_cursor_to_pixels(SpaceImage *sima)
3885 {
3886   int width = 0, height = 0;
3887
3888   ED_space_image_get_size(sima, &width, &height);
3889   uv_snap_to_pixel(sima->cursor, width, height);
3890 }
3891
3892 static bool uv_snap_cursor_to_selection(
3893     Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima)
3894 {
3895   return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around);
3896 }
3897
3898 static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
3899 {
3900   SpaceImage *sima = CTX_wm_space_image(C);
3901
3902   bool changed = false;
3903
3904   switch (RNA_enum_get(op->ptr, "target")) {
3905     case 0:
3906       uv_snap_cursor_to_pixels(sima);
3907       changed = true;
3908       break;
3909     case 1: {
3910       Scene *scene = CTX_data_scene(C);
3911       Image *ima = CTX_data_edit_image(C);
3912       ViewLayer *view_layer = CTX_data_view_layer(C);
3913
3914       uint objects_len = 0;
3915       Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
3916           view_layer, ((View3D *)NULL), &objects_len);
3917       changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima);
3918       MEM_freeN(objects);
3919       break;
3920     }
3921   }
3922
3923   if (!changed) {
3924     return OPERATOR_CANCELLED;
3925   }
3926
3927   WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, sima);
3928
3929   return OPERATOR_FINISHED;
3930 }
3931
3932 static void UV_OT_snap_cursor(wmOperatorType *ot)
3933 {
3934   static const EnumPropertyItem target_items[] = {
3935       {0, "PIXELS", 0, "Pixels", ""},
3936       {1, "SELECTED", 0, "Selected", ""},
3937       {0, NULL, 0, NULL, NULL},
3938   };
3939
3940   /* identifiers */
3941   ot->name = "Snap Cursor";
3942   ot->description = "Snap cursor to target type";
3943   ot->idname = "UV_OT_snap_cursor";
3944   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3945
3946   /* api callbacks */
3947   ot->exec = uv_snap_cursor_exec;
3948   ot->poll = ED_operator_uvedit_space_image; /* requires space image */
3949
3950   /* properties */
3951   RNA_def_enum(
3952       ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
3953 }
3954
3955 /** \} */
3956
3957 /* -------------------------------------------------------------------- */
3958 /** \name Snap Selection Operator
3959  * \{ */
3960
3961 static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2])
3962 {
3963   BMEditMesh *em = BKE_editmesh_from_object(obedit);
3964   BMFace *efa;
3965   BMLoop *l;
3966   BMIter iter, liter;
3967   MLoopUV *luv;
3968   bool changed = false;
3969
3970   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3971
3972   BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3973     if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
3974       continue;
3975     }
3976
3977     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3978       if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
3979         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3980         copy_v2_v2(luv->uv, cursor);
3981         changed = true;
3982       }
3983     }
3984   }
3985
3986   return changed;
3987 }
3988
3989 static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const float offset[2])
3990 {
3991   BMEditMesh *em = BKE_editmesh_from_object(obedit);
3992   BMFace *efa;
3993   BMLoop *l;
3994   BMIter iter, liter;
3995   MLoopUV *luv;
3996   bool changed = false;
3997
3998   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3999
4000   BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4001     if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
4002       continue;
4003     }
4004
4005     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
4006       if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
4007         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4008         add_v2_v2(luv->uv, offset);
4009         changed = true;
4010       }
4011     }
4012   }
4013
4014   return changed;
4015 }
4016
4017 static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
4018 {
4019   BMEditMesh *em = BKE_editmesh_from_object(obedit);
4020   BMesh *bm = em->bm;
4021   BMFace *f;
4022   BMLoop *l, *lsub;
4023   BMIter iter, liter, lsubiter;
4024   MLoopUV *luv;
4025   bool changed = false;
4026   const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
4027
4028   /* index every vert that has a selected UV using it, but only once so as to
4029    * get unique indices and to count how much to malloc */
4030   BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
4031     if (uvedit_face_visible_test(scene, obedit, ima, f)) {
4032       BM_elem_flag_enable(f, BM_ELEM_TAG);
4033       BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
4034         BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
4035       }
4036     }
4037     else {
4038       BM_elem_flag_disable(f, BM_ELEM_TAG);
4039     }
4040   }
4041
4042   BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
4043     if (BM_elem_flag_test(f, BM_ELEM_TAG)) { /* face: visible */
4044       BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
4045         if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* loop: selected*/
4046           float uv[2] = {0.0f, 0.0f};
4047           int uv_tot = 0;
4048
4049           BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) {
4050             if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* face: visible */
4051                 !BM_elem_flag_test(lsub, BM_ELEM_TAG))     /* loop: unselected  */
4052             {
4053               luv = BM_ELEM_CD_GET_VOID_P(lsub, cd_loop_uv_offset);
4054               add_v2_v2(uv, luv->uv);
4055               uv_tot++;
4056             }
4057           }
4058
4059           if (uv_tot) {
4060             luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4061             mul_v2_v2fl(luv->uv, uv, 1.0f / (float)uv_tot);
4062             changed = true;
4063           }
4064         }
4065       }
4066     }
4067   }
4068
4069   return changed;
4070 }
4071
4072 static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
4073 {
4074   BMEditMesh *em = BKE_editmesh_from_object(obedit);
4075   Image *ima = sima->image;
4076   BMFace *efa;
4077   BMLoop *l;
4078   BMIter iter, liter;
4079   MLoopUV *luv;
4080   int width = 0, height = 0;
4081   float w, h;
4082   bool changed = false;
4083
4084   const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
4085
4086   ED_space_image_get_size(sima, &width, &height);
4087   w = (float)width;
4088   h = (float)height;
4089
4090   BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4091     if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
4092       continue;
4093     }
4094
4095     BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
4096       if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
4097         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4098         uv_snap_to_pixel(luv->uv, w, h);
4099       }
4100     }
4101
4102     changed = true;
4103   }
4104
4105   return changed;
4106 }
4107
4108 static int uv_snap_selection_exec(bContext *C, wmOperator *op)
4109 {
4110   Scene *scene = CTX_data_scene(C);
4111   ViewLayer *view_layer = CTX_data_view_layer(C);
4112   SpaceImage *sima = CTX_wm_space_image(C);
4113   Image *ima = CTX_data_edit_image(C);
4114   ToolSettings *ts = scene->toolsettings;
4115   const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
4116   const int target = RNA_enum_get(op->ptr, "target");
4117   float offset[2] = {0};
4118
4119   uint objects_len = 0;
4120   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
4121       view_layer, ((View3D *)NULL), &objects_len);
4122
4123   if (target == 2) {
4124     float center[2];
4125     if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) {
4126       MEM_freeN(objects);
4127       return OPERATOR_CANCELLED;
4128     }
4129     sub_v2_v2v2(offset, sima->cursor, center);
4130   }
4131
4132   bool changed_multi = false;
4133   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4134     Object *obedit = objects[ob_index];
4135     BMEditMesh *em = BKE_editmesh_from_object(obedit);
4136
4137     if (synced_selection && (em->bm->totvertsel == 0)) {
4138       continue;
4139     }
4140
4141     bool changed = false;
4142     switch (target) {
4143       case 0:
4144         changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
4145         break;
4146       case 1:
4147         changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor);
4148         break;
4149       case 2:
4150         changed = uv_snap_uvs_offset(scene, ima, obedit, offset);
4151         break;
4152       case 3:
4153         changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit);
4154         break;
4155     }
4156
4157     if (changed) {
4158       changed_multi = true;
4159       uvedit_live_unwrap_update(sima, scene, obedit);
4160       DEG_id_tag_update(obedit->data, 0);
4161       WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
4162     }
4163   }
4164   MEM_freeN(objects);
4165
4166   return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
4167 }
4168
4169 static void UV_OT_snap_selected(wmOperatorType *ot)
4170 {
4171   static const EnumPropertyItem target_items[] = {
4172       {0, "PIXELS", 0, "Pixels", ""},
4173       {1, "CURSOR", 0, "Cursor", ""},
4174       {2, "CURSOR_OFFSET", 0, "Cursor (Offset)", ""},
4175       {3, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
4176       {0, NULL, 0, NULL, NULL},
4177   };
4178
4179   /* identifiers */
4180   ot->name = "Snap Selection";
4181   ot->description = "Snap selected UV vertices to target type";
4182   ot->idname = "UV_OT_snap_selected";
4183   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4184
4185   /* api callbacks */
4186   ot->exec = uv_snap_selection_exec;
4187   ot->poll = ED_operator_uvedit_space_image;
4188
4189   /* properties */
4190   RNA_def_enum(
4191       ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
4192 }
4193
4194 /** \} */
4195
4196 /* -------------------------------------------------------------------- */
4197 /** \name Pin UV's Operator
4198  * \{ */
4199
4200 static int uv_pin_exec(bContext *C, wmOperator *op)
4201 {
4202   Scene *scene = CTX_data_scene(C);
4203   ViewLayer *view_layer = CTX_data_view_layer(C);
4204   Image *ima = CTX_data_edit_image(C);
4205   BMFace *efa;
4206   BMLoop *l;
4207   BMIter iter, liter;
4208   MLoopUV *luv;
4209   ToolSettings *ts = scene->toolsettings;
4210   const bool clear = RNA_boolean_get(op->ptr, "clear");
4211   const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
4212
4213   uint objects_len = 0;
4214   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
4215       view_layer, ((View3D *)NULL), &objects_len);
4216
4217   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4218     Object *obedit = objects[ob_index];
4219     BMEditMesh *em = BKE_editmesh_from_object(obedit);
4220
4221     bool changed = false;
4222     const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
4223
4224     if (synced_selection && (em->bm->totvertsel == 0)) {
4225       continue;
4226     }
4227
4228     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4229       if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
4230         continue;
4231       }
4232
4233       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
4234         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
4235
4236         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
4237           changed = true;
4238           if (clear) {
4239             luv->flag &= ~MLOOPUV_PINNED;
4240           }
4241           else {
4242             luv->flag |= MLOOPUV_PINNED;
4243           }