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