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