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