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