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