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