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