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