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