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