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