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