committing working copy
[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
48 #include "BKE_context.h"
49 #include "BKE_customdata.h"
50 #include "BKE_depsgraph.h"
51 #include "BKE_image.h"
52 #include "BKE_library.h"
53 #include "BKE_mesh.h"
54 #include "BKE_report.h"
55 #include "BKE_utildefines.h"
56 #include "BKE_tessmesh.h"
57
58 #include "ED_image.h"
59 #include "ED_mesh.h"
60 #include "ED_object.h"
61 #include "ED_screen.h"
62 #include "ED_transform.h"
63
64 #include "RNA_access.h"
65 #include "RNA_define.h"
66
67 #include "WM_api.h"
68 #include "WM_types.h"
69
70 #include "UI_view2d.h"
71
72 #include "uvedit_intern.h"
73
74 #define EFA_F1_FLAG     2
75
76 /************************* state testing ************************/
77
78 int ED_uvedit_test(Object *obedit)
79 {
80         BMEditMesh *em;
81         int ret;
82
83         if(obedit->type != OB_MESH)
84                 return 0;
85
86         em = ((Mesh*)obedit->data)->edit_btmesh;
87         ret = EDBM_texFaceCheck(em);
88         
89         return ret;
90 }
91
92 /************************* assign image ************************/
93
94 void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *previma)
95 {
96         BMEditMesh *em;
97         BMFace *efa;
98         BMIter iter;
99         MTexPoly *tf;
100         int update= 0;
101         
102         /* skip assigning these procedural images... */
103         if(ima && (ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE))
104                 return;
105
106         /* verify we have a mesh we can work with */
107         if(!obedit || (obedit->type != OB_MESH))
108                 return;
109
110         em= ((Mesh*)obedit->data)->edit_btmesh;
111         if(!em || !em->bm->totface) {
112                 return;
113         }
114         
115         /* ensure we have a uv layer */
116         if(!CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) {
117                 BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY);
118                 BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV);
119                 update= 1;
120         }
121
122         /* now assign to all visible faces */
123         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
124                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
125
126                 if(uvedit_face_visible(scene, previma, efa, tf)) {
127                         if(ima) {
128                                 tf->tpage= ima;
129                                 tf->mode |= TF_TEX;
130                                 
131                                 if(ima->id.us==0) id_us_plus(&ima->id);
132                                 else id_lib_extern(&ima->id);
133                         }
134                         else {
135                                 tf->tpage= NULL;
136                                 tf->mode &= ~TF_TEX;
137                         }
138
139                         update = 1;
140                 }
141         }
142
143         /* and update depdency graph */
144         if(update)
145                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
146 }
147
148 /* dotile -     1, set the tile flag (from the space image)
149  *                      2, set the tile index for the faces. */
150 void ED_uvedit_set_tile(bContext *C, Scene *scene, Object *obedit, Image *ima, int curtile)
151 {
152         BMEditMesh *em;
153         BMFace *efa;
154         BMIter iter;
155         MTexPoly *tf;
156         
157         /* verify if we have something to do */
158         if(!ima || !ED_uvedit_test(obedit))
159                 return;
160         
161         /* skip assigning these procedural images... */
162         if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
163                 return;
164         
165         em= ((Mesh*)obedit->data)->edit_btmesh;
166
167         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
168                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
169
170                 if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT))
171                         tf->tile= curtile; /* set tile index */
172         }
173
174         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
175         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
176 }
177
178 /*********************** space conversion *********************/
179
180 static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
181 {
182         int width, height;
183
184         ED_space_image_size(sima, &width, &height);
185
186         dist[0]= pixeldist/width;
187         dist[1]= pixeldist/height;
188 }
189
190 /*************** visibility and selection utilities **************/
191
192 int uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
193 {
194         ToolSettings *ts= scene->toolsettings;
195
196         if(ts->uv_flag & UV_SYNC_SELECTION)
197                 return (BM_TestHFlag(efa, BM_HIDDEN)==0);
198         else
199                 return (BM_TestHFlag(efa, BM_HIDDEN)==0 && BM_TestHFlag(efa, BM_SELECT));
200 }
201
202 int uvedit_face_visible(Scene *scene, Image *ima, BMFace *efa, MTexPoly *tf) {
203         ToolSettings *ts= scene->toolsettings;
204
205         if(ts->uv_flag & UV_SHOW_SAME_IMAGE)
206                 return (tf->tpage==ima)? uvedit_face_visible_nolocal(scene, efa): 0;
207         else
208                 return uvedit_face_visible_nolocal(scene, efa);
209 }
210
211 int uvedit_face_selected(Scene *scene, BMEditMesh *em, BMFace *efa)
212 {
213         ToolSettings *ts= scene->toolsettings;
214
215         if(ts->uv_flag & UV_SYNC_SELECTION)
216                 return (BM_TestHFlag(efa, BM_SELECT));
217         else {
218                 BMLoop *l;
219                 MLoopUV *luv;
220                 BMIter liter;
221
222                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
223                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
224                         if (!(luv->flag & MLOOPUV_VERTSEL))
225                                 return 0;
226                 }
227
228                 return 1;
229         }
230 }
231
232 int uvedit_face_select(Scene *scene, BMEditMesh *em, BMFace *efa)
233 {
234         ToolSettings *ts= scene->toolsettings;
235
236         if(ts->uv_flag & UV_SYNC_SELECTION)
237                 BM_Select(em->bm, efa, 1);
238         else {
239                 BMLoop *l;
240                 MLoopUV *luv;
241                 BMIter liter;
242
243                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
244                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
245                         luv->flag |= MLOOPUV_VERTSEL;
246                 }
247
248                 return 1;
249         }
250
251         return 0;
252 }
253
254 int uvedit_face_deselect(Scene *scene, BMEditMesh *em, BMFace *efa)
255 {
256         ToolSettings *ts= scene->toolsettings;
257
258         if(ts->uv_flag & UV_SYNC_SELECTION)
259                 BM_Select(em->bm, efa, 0);
260         else {
261                 BMLoop *l;
262                 MLoopUV *luv;
263                 BMIter liter;
264
265                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
266                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
267                         luv->flag &= ~MLOOPUV_VERTSEL;
268                 }
269
270                 return 1;
271         }
272
273         return 0;
274 }
275
276 int uvedit_edge_selected(BMEditMesh *em, Scene *scene, BMLoop *l)
277 {
278         ToolSettings *ts= scene->toolsettings;
279
280         if(ts->uv_flag & UV_SYNC_SELECTION) {
281                 if(ts->selectmode == SCE_SELECT_FACE)
282                         return BM_TestHFlag(l->f, BM_SELECT);
283                 else if(ts->selectmode == SCE_SELECT_EDGE) {
284                         return BM_TestHFlag(l->e, BM_SELECT);
285                 } else
286                         return BM_TestHFlag(l->v, BM_SELECT) && 
287                                BM_TestHFlag(((BMLoop*)l->next)->v, BM_SELECT);
288         }
289         else {
290                 MLoopUV *luv1, *luv2;
291
292                 luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
293                 luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
294
295                 return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
296         }
297 }
298
299 void uvedit_edge_select(BMEditMesh *em, Scene *scene, BMLoop *l)
300
301 {
302         ToolSettings *ts= scene->toolsettings;
303
304         if(ts->uv_flag & UV_SYNC_SELECTION) {
305                 if(ts->selectmode == SCE_SELECT_FACE)
306                         BM_Select(em->bm, l->f, 1);
307                 else if(ts->selectmode == SCE_SELECT_EDGE)
308                         BM_Select(em->bm, l->e, 1);
309                 else {
310                         BM_Select(em->bm, l->e->v1, 1);
311                         BM_Select(em->bm, l->e->v2, 1);
312                 }
313         }
314         else {
315                 MLoopUV *luv1, *luv2;
316
317                 luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
318                 luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
319                 
320                 luv1->flag |= MLOOPUV_VERTSEL;
321                 luv2->flag |= MLOOPUV_VERTSEL;
322         }
323 }
324
325 void uvedit_edge_deselect(BMEditMesh *em, Scene *scene, BMLoop *l)
326
327 {
328         ToolSettings *ts= scene->toolsettings;
329
330         if(ts->uv_flag & UV_SYNC_SELECTION) {
331                 if(ts->selectmode == SCE_SELECT_FACE)
332                         BM_Select(em->bm, l->f, 0);
333                 else if(ts->selectmode == SCE_SELECT_EDGE)
334                         BM_Select(em->bm, l->e, 0);
335                 else {
336                         BM_Select(em->bm, l->e->v1, 0);
337                         BM_Select(em->bm, l->e->v2, 0);
338                 }
339         }
340         else {
341                 MLoopUV *luv1, *luv2;
342
343                 luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
344                 luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
345                 
346                 luv1->flag &= ~MLOOPUV_VERTSEL;
347                 luv2->flag &= ~MLOOPUV_VERTSEL;
348         }
349 }
350
351 int uvedit_uv_selected(BMEditMesh *em, Scene *scene, BMLoop *l)
352 {
353         ToolSettings *ts= scene->toolsettings;
354
355         if(ts->uv_flag & UV_SYNC_SELECTION) {
356                 if(ts->selectmode == SCE_SELECT_FACE)
357                         return BM_TestHFlag(l->f, BM_SELECT);
358                 else
359                         return BM_TestHFlag(l, BM_SELECT);
360         }
361         else {
362                 MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
363
364                 return luv->flag & MLOOPUV_VERTSEL;
365         }
366 }
367
368 void uvedit_uv_select(BMEditMesh *em, Scene *scene, BMLoop *l)
369 {
370         ToolSettings *ts= scene->toolsettings;
371
372         if(ts->uv_flag & UV_SYNC_SELECTION) {
373                 if(ts->selectmode == SCE_SELECT_FACE)
374                         BM_Select(em->bm, l->f, 1);
375                 else
376                         BM_Select(em->bm, l->v, 1);
377         }
378         else {
379                 MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
380                 
381                 luv->flag |= MLOOPUV_VERTSEL;
382         }
383 }
384
385 void uvedit_uv_deselect(BMEditMesh *em, Scene *scene, BMLoop *l)
386 {
387         ToolSettings *ts= scene->toolsettings;
388
389         if(ts->uv_flag & UV_SYNC_SELECTION) {
390                 if(ts->selectmode == SCE_SELECT_FACE)
391                         BM_Select(em->bm, l->f, 0);
392                 else
393                         BM_Select(em->bm, l->v, 0);
394         }
395         else {
396                 MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
397                 
398                 luv->flag &= ~MLOOPUV_VERTSEL;
399         }
400 }
401
402 /*********************** geometric utilities ***********************/
403 void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2])
404 {
405         BMLoop *l;
406         MLoopUV *luv;
407         BMIter liter;
408
409         cent[0] = cent[1] = 0.0f;
410
411         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
412                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
413                 cent[0] += luv->uv[0];
414                 cent[1] += luv->uv[1];
415         }
416
417         cent[0] /= (float) f->len;
418         cent[1] /= (float) f->len;
419 }
420
421
422 void uv_center(float uv[][2], float cent[2], int quad)
423 {
424         if(quad) {
425                 cent[0] = (uv[0][0] + uv[1][0] + uv[2][0] + uv[3][0]) / 4.0;
426                 cent[1] = (uv[0][1] + uv[1][1] + uv[2][1] + uv[3][1]) / 4.0;            
427         }
428         else {
429                 cent[0] = (uv[0][0] + uv[1][0] + uv[2][0]) / 3.0;
430                 cent[1] = (uv[0][1] + uv[1][1] + uv[2][1]) / 3.0;               
431         }
432 }
433
434 float uv_area(float uv[][2], int quad)
435 {
436         if(quad)
437                 return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); 
438         else
439                 return area_tri_v2(uv[0], uv[1], uv[2]); 
440 }
441
442 float poly_uv_area(float uv[][2], int len)
443 {
444         //BMESH_TODO: make this not suck
445         //maybe use scanfill? I dunno.
446
447         if(len >= 4)
448                 return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); 
449         else
450                 return area_tri_v2(uv[0], uv[1], uv[2]); 
451
452         return 1.0;
453 }
454
455 void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
456 {
457         int i;
458         for (i=0; i<len; i++) {
459                 uv[i][0] = uv_orig[i][0]*aspx;
460                 uv[i][1] = uv_orig[i][1]*aspy;
461         }
462 }
463
464 void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy)
465 {
466         uv[0][0] = uv_orig[0][0]*aspx;
467         uv[0][1] = uv_orig[0][1]*aspy;
468         
469         uv[1][0] = uv_orig[1][0]*aspx;
470         uv[1][1] = uv_orig[1][1]*aspy;
471         
472         uv[2][0] = uv_orig[2][0]*aspx;
473         uv[2][1] = uv_orig[2][1]*aspy;
474         
475         uv[3][0] = uv_orig[3][0]*aspx;
476         uv[3][1] = uv_orig[3][1]*aspy;
477 }
478
479 int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
480 {
481         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
482         BMFace *efa;
483         BMLoop *l;
484         BMIter iter, liter;
485         MTexPoly *tf;
486         MLoopUV *luv;
487         int sel;
488
489         INIT_MINMAX2(min, max);
490
491         sel= 0;
492         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
493                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
494                 if(!uvedit_face_visible(scene, ima, efa, tf))
495                         continue;
496                 
497                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
498                         if (uvedit_uv_selected(em, scene, l)) 
499                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
500                                 DO_MINMAX2(luv->uv, min, max); 
501                                 sel = 1;
502                         }
503         }
504
505         return sel;
506 }
507
508 int uvedit_center(Scene *scene, Image *ima, Object *obedit, 
509                   float *cent, int mode)
510 {
511         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
512         BMFace *efa;
513         BMLoop *l;
514         BMIter iter, liter;
515         MTexPoly *tf;
516         MLoopUV *luv;
517         float min[2], max[2];
518         int change= 0;
519         
520         if(mode==0) {
521                 if(ED_uvedit_minmax(scene, ima, obedit, min, max))
522                         change = 1;
523         }
524         else if(mode==1) {
525                 INIT_MINMAX2(min, max);
526                 
527                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
528                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
529                         if(!uvedit_face_visible(scene, ima, efa, tf))
530                                 continue;
531                         
532                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
533                                 if (uvedit_uv_selected(em, scene, l)) {
534                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
535         
536                                         DO_MINMAX2(luv->uv, min, max); 
537                                         change= 1;
538                                 }
539                         }
540                 }
541         }
542         
543         if(change) {
544                 cent[0]= (min[0]+max[0])/2.0;
545                 cent[1]= (min[1]+max[1])/2.0;
546                 
547                 return 1;
548         }
549
550         return 0;
551 }
552
553 /************************** find nearest ****************************/
554
555 typedef struct NearestHit {
556         BMFace *efa;
557         MTexPoly *tf;
558         BMLoop *l, *nextl;
559         MLoopUV *luv, *nextluv;
560         int lindex; //index of loop within face
561         int vert1, vert2; //index in mesh of edge vertices
562 } NearestHit;
563
564 static void find_nearest_uv_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
565 {
566         MTexPoly *tf;
567         BMFace *efa;
568         BMLoop *l;
569         BMVert *eve;
570         BMIter iter, liter;
571         MLoopUV *luv, *nextluv;
572         float mindist, dist;
573         int i;
574
575         mindist= 1e10f;
576         memset(hit, 0, sizeof(*hit));
577
578         eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
579         for (i=0; eve; eve=BMIter_Step(&iter), i++) {
580                 BMINDEX_SET(eve, i);
581         }
582         
583         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
584                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
585                 if(!uvedit_face_visible(scene, ima, efa, tf))
586                         continue;
587                 
588                 i = 0;
589                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
590                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
591                         nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
592
593                         dist= dist_to_line_segment_v2(co, luv->uv, nextluv->uv);
594
595                         if(dist < mindist) {
596                                 hit->tf= tf;
597                                 hit->efa= efa;
598                                 
599                                 hit->l = l;
600                                 hit->nextl = (BMLoop*)l->next;
601                                 hit->luv = luv;
602                                 hit->nextluv = nextluv;
603                                 hit->lindex = i;
604                                 hit->vert1 = BMINDEX_GET(hit->l->v);
605                                 hit->vert2 = BMINDEX_GET(((BMLoop*)hit->l->next)->v);
606
607                                 mindist = dist;
608                         }
609
610                         i++;
611                 }
612         }
613 }
614
615 static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
616 {
617         MTexPoly *tf;
618         BMFace *efa;
619         BMLoop *l;
620         BMIter iter, liter;
621         MLoopUV *luv;
622         float mindist, dist, cent[2];
623
624         mindist= 1e10f;
625         memset(hit, 0, sizeof(*hit));
626
627         /*this will fill in hit.vert1 and hit.vert2*/
628         find_nearest_uv_edge(scene, ima, em, co, hit);
629         hit->l = hit->nextl = NULL;
630         hit->luv = hit->nextluv = NULL;
631
632         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
633                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
634                 if(!uvedit_face_visible(scene, ima, efa, tf))
635                         continue;
636                 
637                 cent[0]= cent[1]= 0.0f;
638                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
639                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
640
641                         cent[0] += luv->uv[0];
642                         cent[1] += luv->uv[1];
643                 }
644
645                 cent[0] /= efa->len;
646                 cent[1] /= efa->len;
647                 dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
648
649                 if(dist < mindist) {
650                         hit->tf= tf;
651                         hit->efa= efa;
652                         mindist= dist;
653                 }
654         }
655 }
656
657 static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int nverts, int id, 
658                               float co[2], float uv[2])
659 {
660         BMLoop *l;
661         MLoopUV *luv;
662         BMIter iter;
663         float m[3], v1[3], v2[3], c1, c2, *uv1, *uv2, *uv3;
664         int id1, id2, i;
665
666         id1= (id+efa->len-1)%efa->len;
667         id2= (id+efa->len+1)%efa->len;
668
669         m[0]= co[0]-uv[0];
670         m[1]= co[1]-uv[1];
671
672         i = 0;
673         BM_ITER(l, &iter, em->bm, BM_LOOPS_OF_FACE, efa) {
674                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
675                 
676                 if (i == id1)
677                         uv1 = luv->uv;
678                 else if (i == id)
679                         uv2 = luv->uv;
680                 else if (i == id2)
681                         uv3 = luv->uv;
682
683                 i++;
684         }
685
686         sub_v3_v3v3(v1, uv1, uv);
687         sub_v3_v3v3(v2, uv3, uv);
688
689         /* m and v2 on same side of v-v1? */
690         c1= v1[0]*m[1] - v1[1]*m[0];
691         c2= v1[0]*v2[1] - v1[1]*v2[0];
692
693         if(c1*c2 < 0.0f)
694                 return 0;
695
696         /* m and v1 on same side of v-v2? */
697         c1= v2[0]*m[1] - v2[1]*m[0];
698         c2= v2[0]*v1[1] - v2[1]*v1[0];
699
700         return (c1*c2 >= 0.0f);
701 }
702
703 static void find_nearest_uv_vert(Scene *scene, Image *ima, BMEditMesh *em, 
704                                  float co[2], float penalty[2], NearestHit *hit)
705 {
706         BMFace *efa;
707         BMVert *eve;
708         BMLoop *l;
709         BMIter iter, liter;
710         MTexPoly *tf;
711         MLoopUV *luv;
712         float mindist, dist;
713         int i, nverts;
714
715         /*this will fill in hit.vert1 and hit.vert2*/
716         find_nearest_uv_edge(scene, ima, em, co, hit);
717         hit->l = hit->nextl = NULL;
718         hit->luv = hit->nextluv = NULL;
719
720         mindist= 1e10f;
721         memset(hit, 0, sizeof(*hit));
722         
723         eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
724         for (i=0; eve; eve=BMIter_Step(&iter), i++) {
725                 BMINDEX_SET(eve, i);
726         }
727
728         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
729                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
730                 if(!uvedit_face_visible(scene, ima, efa, tf))
731                         continue;
732                 
733                 i = 0;
734                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
735                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
736
737                         if(penalty && uvedit_uv_selected(em, scene, l))
738                                 dist= fabs(co[0]-luv->uv[0])+penalty[0] + fabs(co[1]-luv->uv[1])+penalty[1];
739                         else
740                                 dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
741
742                         if(dist<=mindist) {
743                                 if(dist==mindist)
744                                         if(!nearest_uv_between(em, efa, efa->len, i, co, luv->uv)) {
745                                                 i++;
746                                                 continue;
747                                         }
748
749                                 mindist= dist;
750
751                                 hit->l = l;
752                                 hit->nextl = (BMLoop*)l->next;
753                                 hit->luv = luv;
754                                 hit->nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
755                                 hit->tf= tf;
756                                 hit->efa= efa;
757                                 hit->lindex = i;
758                                 hit->vert1 = BMINDEX_GET(hit->l->v);
759                         }
760
761                         i++;
762                 }
763         }
764 }
765
766 int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
767 {
768         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
769         BMFace *efa;
770         BMLoop *l;
771         BMIter iter, liter;
772         MTexPoly *tf;
773         MLoopUV *luv;
774         float mindist, dist;
775         int found= 0;
776
777         mindist= 1e10f;
778         uv[0]= co[0];
779         uv[1]= co[1];
780         
781         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
782                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
783                 if(!uvedit_face_visible(scene, ima, efa, tf))
784                         continue;
785                 
786                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
787                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
788                         dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
789
790                         if(dist<=mindist) {
791                                 mindist= dist;
792
793                                 uv[0]= luv->uv[0];
794                                 uv[1]= luv->uv[1];
795                                 found= 1;
796                         }
797                 }
798         }
799
800         return found;
801 }
802
803 /*********************** loop select ***********************/
804
805 static void uv_vertex_loop_flag(UvMapVert *first)
806 {
807         UvMapVert *iterv;
808         int count= 0;
809
810         for(iterv=first; iterv; iterv=iterv->next) {
811                 if(iterv->separate && iterv!=first)
812                         break;
813
814                 count++;
815         }
816         
817         if(count < 5)
818                 first->flag= 1;
819 }
820
821 static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, BMFace *efa, int a)
822 {
823         UvMapVert *iterv, *first;
824         BMLoop *l;
825
826         l = BMIter_AtIndex(NULL, BM_LOOPS_OF_FACE, efa, a);
827         first= EDBM_get_uv_map_vert(vmap,  BMINDEX_GET(l->v));
828
829         for(iterv=first; iterv; iterv=iterv->next) {
830                 if(iterv->separate)
831                         first= iterv;
832                 if(iterv->f == BMINDEX_GET(efa))
833                         return first;
834         }
835         
836         return NULL;
837 }
838
839 static int uv_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface)
840 {
841         UvMapVert *iterv1, *iterv2;
842         BMFace *efa;
843         int tot = 0;
844
845         /* count number of faces this edge has */
846         for(iterv1=first1; iterv1; iterv1=iterv1->next) {
847                 if(iterv1->separate && iterv1 != first1)
848                         break;
849
850                 for(iterv2=first2; iterv2; iterv2=iterv2->next) {
851                         if(iterv2->separate && iterv2 != first2)
852                                 break;
853
854                         if(iterv1->f == iterv2->f) {
855                                 /* if face already tagged, don't do this edge */
856                                 efa= EDBM_get_face_for_index(em, iterv1->f);
857                                 if(BMO_TestFlag(em->bm, efa, EFA_F1_FLAG))
858                                         return 0;
859
860                                 tot++;
861                                 break;
862                         }
863                 }
864         }
865
866         if(*totface == 0) /* start edge */
867                 *totface= tot;
868         else if(tot != *totface) /* check for same number of faces as start edge */
869                 return 0;
870
871         /* tag the faces */
872         for(iterv1=first1; iterv1; iterv1=iterv1->next) {
873                 if(iterv1->separate && iterv1 != first1)
874                         break;
875
876                 for(iterv2=first2; iterv2; iterv2=iterv2->next) {
877                         if(iterv2->separate && iterv2 != first2)
878                                 break;
879
880                         if(iterv1->f == iterv2->f) {
881                                 efa= EDBM_get_face_for_index(em, iterv1->f);
882                                 BMO_SetFlag(em->bm, efa, EFA_F1_FLAG);
883                                 break;
884                         }
885                 }
886         }
887
888         return 1;
889 }
890
891 static int select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit, float limit[2], int extend)
892 {
893         BMVert *eve;
894         BMFace *efa;
895         BMIter iter, liter;
896         BMLoop *l;
897         MTexPoly *tf;
898         UvVertMap *vmap;
899         UvMapVert *iterv1, *iterv2;
900         int a, count, looking, nverts, starttotf, select;
901
902         /* setup */
903         EDBM_init_index_arrays(em, 0, 0, 1);
904         vmap= EDBM_make_uv_vert_map(em, 0, 0, limit);
905
906         count = 0;
907         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
908                 BMINDEX_SET(eve, count);
909                 count++;
910         }
911
912         count = 0;
913         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
914                 if(!extend) {
915                         uvedit_face_deselect(scene, em, efa);
916                 }
917                 
918                 BMO_ClearFlag(em->bm, efa, EFA_F1_FLAG);
919                 BMINDEX_SET(efa, count);
920                 count++;
921         }
922
923         /* set flags for first face and verts */
924         nverts= hit->efa->len;
925         iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
926         iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
927         uv_vertex_loop_flag(iterv1);
928         uv_vertex_loop_flag(iterv2);
929
930         starttotf= 0;
931         uv_edge_tag_faces(em, iterv1, iterv2, &starttotf);
932
933         /* sorry, first edge isnt even ok */
934         if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
935         else looking= 1;
936
937         /* iterate */
938         while(looking) {
939                 looking= 0;
940
941                 /* find correct valence edges which are not tagged yet, but connect to tagged one */
942
943                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
944                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
945
946                         if(!BMO_TestFlag(em->bm, efa, EFA_F1_FLAG) && uvedit_face_visible(scene, ima, efa, tf)) {
947                                 nverts= efa->len;
948                                 for(a=0; a<nverts; a++) {
949                                         /* check face not hidden and not tagged */
950                                         iterv1= uv_vertex_map_get(vmap, efa, a);
951                                         iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
952                                         
953                                         if (!iterv1 || !iterv2)
954                                                 continue;
955
956                                         /* check if vertex is tagged and has right valence */
957                                         if(iterv1->flag || iterv2->flag) {
958                                                 if(uv_edge_tag_faces(em, iterv1, iterv2, &starttotf)) {
959                                                         looking= 1;
960                                                         BMO_SetFlag(em->bm, efa, EFA_F1_FLAG);
961
962                                                         uv_vertex_loop_flag(iterv1);
963                                                         uv_vertex_loop_flag(iterv2);
964                                                         break;
965                                                 }
966                                         }
967                                 }
968                         }
969                 }
970         }
971
972         /* do the actual select/deselect */
973         nverts= hit->efa->len;
974         iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
975         iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
976         iterv1->flag= 1;
977         iterv2->flag= 1;
978
979         if(extend) {
980                 if(uvedit_uv_selected(em, scene, hit->l) && uvedit_uv_selected(em, scene, hit->l))
981                         select= 0;
982                 else
983                         select= 1;
984         }
985         else
986                 select= 1;
987         
988         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
989                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
990
991                 a = 0;
992                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
993                         iterv1= uv_vertex_map_get(vmap, efa, a);
994
995                         if(iterv1->flag) {
996                                 if(select) uvedit_uv_select(em, scene, l);
997                                 else uvedit_uv_deselect(em, scene, l);
998                         }
999
1000                         a++;
1001                 }
1002         }
1003
1004         /* cleanup */
1005         EDBM_free_uv_vert_map(vmap);
1006         EDBM_free_index_arrays(em);
1007
1008         return (select)? 1: -1;
1009 }
1010
1011 /*********************** linked select ***********************/
1012
1013 static void select_linked(Scene *scene, Image *ima, BMEditMesh *em, float limit[2], NearestHit *hit, int extend)
1014 {
1015         BMFace *efa;
1016         BMLoop *l;
1017         BMIter iter, liter;
1018         MTexPoly *tf;
1019         MLoopUV *luv;
1020         UvVertMap *vmap;
1021         UvMapVert *vlist, *iterv, *startv;
1022         int a, i, nverts, stacksize= 0, *stack;
1023         char *flag;
1024
1025         EDBM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
1026         vmap= EDBM_make_uv_vert_map(em, 1, 1, limit);
1027
1028         if(vmap == NULL)
1029                 return;
1030
1031         stack= MEM_mallocN(sizeof(*stack)*em->bm->totface, "UvLinkStack");
1032         flag= MEM_callocN(sizeof(*flag)*em->bm->totface, "UvLinkFlag");
1033
1034         if(!hit) {
1035                 a = 0;
1036                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1037                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1038
1039                         if(uvedit_face_visible(scene, ima, efa, tf)) { 
1040                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1041                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1042
1043                                         if (luv->flag & MLOOPUV_VERTSEL) {
1044                                                 stack[stacksize]= a;
1045                                                 stacksize++;
1046                                                 flag[a]= 1;
1047
1048                                                 break;
1049                                         }
1050                                 }
1051                         }
1052                 }
1053                 a++;
1054         }
1055         else {
1056                 a = 0;
1057                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1058                         if(efa == hit->efa) {
1059                                 stack[stacksize]= a;
1060                                 stacksize++;
1061                                 flag[a]= 1;
1062                                 break;
1063                         }
1064
1065                         a++;
1066                 }
1067         }
1068
1069         while(stacksize > 0) {
1070                 int j;
1071
1072                 stacksize--;
1073                 a= stack[stacksize];
1074                 
1075                 j = 0;
1076                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1077                         if(j==a)
1078                                 break;
1079
1080                         j++;
1081                 }
1082
1083                 nverts= efa->len;
1084
1085                 i = 0;
1086                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1087
1088                         /* make_uv_vert_map_EM sets verts tmp.l to the indicies */
1089                         vlist= EDBM_get_uv_map_vert(vmap, BMINDEX_GET(l->v));
1090                         
1091                         startv= vlist;
1092
1093                         for(iterv=vlist; iterv; iterv=iterv->next) {
1094                                 if(iterv->separate)
1095                                         startv= iterv;
1096                                 if(iterv->f == a)
1097                                         break;
1098                         }
1099
1100                         for(iterv=startv; iterv; iterv=iterv->next) {
1101                                 if((startv != iterv) && (iterv->separate))
1102                                         break;
1103                                 else if(!flag[iterv->f]) {
1104                                         flag[iterv->f]= 1;
1105                                         stack[stacksize]= iterv->f;
1106                                         stacksize++;
1107                                 }
1108                         }
1109
1110                         i++;
1111                 }
1112         }
1113
1114         if(!extend || hit) {            
1115                 a = 0;
1116                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1117                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1118                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1119                                 
1120                                 if (flag[a])
1121                                         luv->flag |= MLOOPUV_VERTSEL;
1122                                 else
1123                                         luv->flag &= ~MLOOPUV_VERTSEL;
1124                         }
1125                 }
1126         }
1127         else {
1128                 a = 0;
1129                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1130                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1131                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1132                                                 
1133                                 if (luv->flag & MLOOPUV_VERTSEL)
1134                                         break;
1135                         }
1136
1137                         a++;
1138                 }
1139
1140                 if(efa) {
1141                         a = 0;
1142                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1143                                 if (!flag[a]) continue;
1144
1145                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1146                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1147                                         
1148                                         luv->flag &= ~MLOOPUV_VERTSEL;
1149                                 }
1150
1151                                 a++;
1152                         }
1153                 }
1154                 else {
1155                         a = 0;
1156                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1157                                 if (!flag[a]) continue;
1158
1159                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1160                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1161                                         
1162                                         luv->flag |= MLOOPUV_VERTSEL;
1163                                 }
1164
1165                                 a++;
1166                         }
1167                 }
1168         }
1169         
1170         MEM_freeN(stack);
1171         MEM_freeN(flag);
1172         EDBM_free_uv_vert_map(vmap);
1173         EDBM_free_index_arrays(em);
1174 }
1175
1176 /* ******************** align operator **************** */
1177
1178 static void weld_align_uv(bContext *C, int tool)
1179 {
1180         Scene *scene;
1181         Object *obedit;
1182         Image *ima;
1183         BMEditMesh *em;
1184         BMFace *efa;
1185         BMLoop *l;
1186         BMIter iter, liter;
1187         MTexPoly *tf;
1188         MLoopUV *luv;
1189         float cent[2], min[2], max[2];
1190         
1191         scene= CTX_data_scene(C);
1192         obedit= CTX_data_edit_object(C);
1193         em= ((Mesh*)obedit->data)->edit_btmesh;
1194         ima= CTX_data_edit_image(C);
1195
1196         INIT_MINMAX2(min, max);
1197
1198         if(tool == 'a') {
1199                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1200                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1201
1202                         if(!uvedit_face_visible(scene, ima, efa, tf))
1203                                 continue;
1204
1205                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1206                                 if (uvedit_uv_selected(em, scene, l)) {
1207                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1208                                         DO_MINMAX2(luv->uv, min, max)
1209                                 }
1210                         }
1211                 }
1212
1213                 tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
1214         }
1215
1216         uvedit_center(scene, ima, obedit, cent, 0);
1217
1218         if(tool == 'x' || tool == 'w') {
1219                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1220                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1221                         if(!uvedit_face_visible(scene, ima, efa, tf))
1222                                 continue;
1223
1224                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1225                                 if (uvedit_uv_selected(em, scene, l)) {
1226                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1227                                         luv->uv[0] = cent[0];
1228                                 }
1229
1230                         }
1231                 }
1232         }
1233
1234         if(tool == 'y' || tool == 'w') {
1235                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1236                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1237                         if(!uvedit_face_visible(scene, ima, efa, tf))
1238                                 continue;
1239
1240                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1241                                 if (uvedit_uv_selected(em, scene, l)) {
1242                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1243                                         luv->uv[1] = cent[1];
1244                                 }
1245
1246                         }
1247                 }
1248         }
1249
1250         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1251         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1252 }
1253
1254 static int align_exec(bContext *C, wmOperator *op)
1255 {
1256         weld_align_uv(C, RNA_enum_get(op->ptr, "axis"));
1257
1258         return OPERATOR_FINISHED;
1259 }
1260
1261 void UV_OT_align(wmOperatorType *ot)
1262 {
1263         static EnumPropertyItem axis_items[] = {
1264                 {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"},
1265                 {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
1266                 {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
1267                 {0, NULL, 0, NULL, NULL}};
1268
1269         /* identifiers */
1270         ot->name= "Align";
1271         ot->description= "Align selected UV vertices to an axis";
1272         ot->idname= "UV_OT_align";
1273         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1274         
1275         /* api callbacks */
1276         ot->exec= align_exec;
1277         ot->poll= ED_operator_uvedit;
1278
1279         /* properties */
1280         RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on.");
1281 }
1282
1283 /* ******************** weld operator **************** */
1284
1285 static int weld_exec(bContext *C, wmOperator *op)
1286 {
1287         weld_align_uv(C, 'w');
1288
1289         return OPERATOR_FINISHED;
1290 }
1291
1292 void UV_OT_weld(wmOperatorType *ot)
1293 {
1294         /* identifiers */
1295         ot->name= "Weld";
1296         ot->description= "Weld selected UV vertices together";
1297         ot->idname= "UV_OT_weld";
1298         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1299         
1300         /* api callbacks */
1301         ot->exec= weld_exec;
1302         ot->poll= ED_operator_uvedit;
1303 }
1304
1305 /* ******************** stitch operator **************** */
1306
1307 /* just for averaging UVs */
1308 typedef struct UVVertAverage {
1309         float uv[2];
1310         int count;
1311 } UVVertAverage;
1312
1313 static int stitch_exec(bContext *C, wmOperator *op)
1314 {
1315         SpaceImage *sima;
1316         Scene *scene;
1317         Object *obedit;
1318         BMEditMesh *em;
1319         BMFace *efa;
1320         BMLoop *l;
1321         BMIter iter, liter;
1322         BMVert *eve;
1323         Image *ima;
1324         MTexPoly *tf;
1325         MLoopUV *luv;
1326         
1327         sima= CTX_wm_space_image(C);
1328         scene= CTX_data_scene(C);
1329         obedit= CTX_data_edit_object(C);
1330         em= ((Mesh*)obedit->data)->edit_btmesh;
1331         ima= CTX_data_edit_image(C);
1332         
1333         if(RNA_boolean_get(op->ptr, "use_limit")) {
1334                 UvVertMap *vmap;
1335                 UvMapVert *vlist, *iterv;
1336                 float newuv[2], limit[2], pixels;
1337                 int a, vtot;
1338
1339                 pixels= RNA_float_get(op->ptr, "limit");
1340                 uvedit_pixel_to_float(sima, limit, pixels);
1341
1342                 EDBM_init_index_arrays(em, 0, 0, 1);
1343                 vmap= EDBM_make_uv_vert_map(em, 1, 0, limit);
1344
1345                 if(vmap == NULL) {
1346                         return OPERATOR_CANCELLED;
1347                 }
1348                 
1349                 a = 0;
1350                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1351                         vlist= EDBM_get_uv_map_vert(vmap, a);
1352
1353                         while(vlist) {
1354                                 newuv[0]= 0; newuv[1]= 0;
1355                                 vtot= 0;
1356
1357                                 for(iterv=vlist; iterv; iterv=iterv->next) {
1358                                         if((iterv != vlist) && iterv->separate)
1359                                                 break;
1360
1361                                         efa = EDBM_get_face_for_index(em, iterv->f);
1362                                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1363                                         
1364                                         l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
1365                                         if (uvedit_uv_selected(em, scene, l)) {
1366                                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1367
1368                                                 newuv[0] += luv->uv[0];
1369                                                 newuv[1] += luv->uv[1];
1370                                                 vtot++;
1371                                         }
1372                                 }
1373
1374                                 if(vtot > 1) {
1375                                         newuv[0] /= vtot; newuv[1] /= vtot;
1376
1377                                         for(iterv=vlist; iterv; iterv=iterv->next) {
1378                                                 if((iterv != vlist) && iterv->separate)
1379                                                         break;
1380
1381                                                 efa = EDBM_get_face_for_index(em, iterv->f);
1382                                                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1383                                                 
1384                                                 l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
1385                                                 if (uvedit_uv_selected(em, scene, l)) {
1386                                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1387
1388                                                         luv->uv[0] = newuv[0];
1389                                                         luv->uv[1] = newuv[1];
1390                                                         vtot++;
1391                                                 }
1392                                         }
1393                                 }
1394
1395                                 vlist= iterv;
1396                         }
1397
1398                         a++;
1399                 }
1400
1401                 EDBM_free_uv_vert_map(vmap);
1402                 EDBM_free_index_arrays(em);
1403         }
1404         else {
1405                 UVVertAverage *uv_average, *uvav;
1406                 int count;
1407
1408                 // index and count verts
1409                 count=0;
1410                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1411                         BMINDEX_SET(eve, count);
1412                         count++;
1413                 }
1414                 
1415                 uv_average= MEM_callocN(sizeof(UVVertAverage)*count, "Stitch");
1416                 
1417                 // gather uv averages per vert
1418                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1419                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1420                         if(!uvedit_face_visible(scene, ima, efa, tf))
1421                                 continue;
1422                         
1423                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1424                                 if(uvedit_uv_selected(em, scene, l)) {
1425                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1426                                         uvav = uv_average + BMINDEX_GET(l->v);
1427
1428                                         uvav->count++;
1429                                         uvav->uv[0] += luv->uv[0];
1430                                         uvav->uv[1] += luv->uv[1];
1431                                 }
1432                         }
1433                 }
1434                 
1435                 // apply uv welding
1436                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1437                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1438                         if(!uvedit_face_visible(scene, ima, efa, tf))
1439                                 continue;
1440                         
1441                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1442                                 if(uvedit_uv_selected(em, scene, l)) {
1443                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1444                                         uvav = uv_average + BMINDEX_GET(l->v);
1445                                         luv->uv[0] = uvav->uv[0]/uvav->count;
1446                                         luv->uv[1] = uvav->uv[1]/uvav->count;
1447                                 }
1448                         }
1449                 }
1450
1451                 MEM_freeN(uv_average);
1452         }
1453
1454         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1455         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1456
1457         return OPERATOR_FINISHED;
1458 }
1459
1460 void UV_OT_stitch(wmOperatorType *ot)
1461 {
1462         /* identifiers */
1463         ot->name= "Stitch";
1464         ot->description= "Stitch selected UV vertices by proximity";
1465         ot->idname= "UV_OT_stitch";
1466         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1467         
1468         /* api callbacks */
1469         ot->exec= stitch_exec;
1470         ot->poll= ED_operator_uvedit;
1471
1472         /* properties */
1473         RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance.");
1474         RNA_def_float(ot->srna, "limit", 20.0, 0.0f, FLT_MAX, "Limit", "Limit distance in image pixels.", -FLT_MAX, FLT_MAX);
1475 }
1476
1477 /* ******************** (de)select all operator **************** */
1478
1479 static int select_inverse_exec(bContext *C, wmOperator *op)
1480 {
1481         Scene *scene;
1482         ToolSettings *ts;
1483         Object *obedit;
1484         BMEditMesh *em;
1485         BMFace *efa;
1486         BMLoop *l;
1487         BMIter iter, liter;
1488         Image *ima;
1489         MTexPoly *tf;
1490         MLoopUV *luv;
1491         
1492         scene= CTX_data_scene(C);
1493         ts= CTX_data_tool_settings(C);
1494         obedit= CTX_data_edit_object(C);
1495         em= ((Mesh*)obedit->data)->edit_btmesh;
1496         ima= CTX_data_edit_image(C);
1497
1498         if(ts->uv_flag & UV_SYNC_SELECTION) {
1499                 EDBM_select_swap(em);
1500         }
1501         else {
1502                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1503                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1504
1505                         if(!uvedit_face_visible(scene, ima, efa, tf))
1506                                 continue;
1507
1508                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1509                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1510                                 luv->flag = luv->flag ^ MLOOPUV_VERTSEL;
1511                         }
1512                 }
1513         }
1514
1515         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1516
1517         return OPERATOR_FINISHED;
1518 }
1519
1520 void UV_OT_select_inverse(wmOperatorType *ot)
1521 {
1522         /* identifiers */
1523         ot->name= "Select Inverse";
1524         ot->description= "Select inverse of (un)selected UV vertices";
1525         ot->idname= "UV_OT_select_inverse";
1526         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1527         
1528         /* api callbacks */
1529         ot->exec= select_inverse_exec;
1530         ot->poll= ED_operator_uvedit;
1531 }
1532
1533 /* ******************** (de)select all operator **************** */
1534
1535 static int select_all_exec(bContext *C, wmOperator *op)
1536 {
1537         Scene *scene;
1538         ToolSettings *ts;
1539         Object *obedit;
1540         BMEditMesh *em;
1541         BMFace *efa;
1542         BMLoop *l;
1543         BMIter iter, liter;
1544         Image *ima;
1545         MTexPoly *tf;
1546         MLoopUV *luv;
1547         int action = RNA_enum_get(op->ptr, "action");
1548         int sel = 1;
1549         
1550         scene= CTX_data_scene(C);
1551         ts= CTX_data_tool_settings(C);
1552         obedit= CTX_data_edit_object(C);
1553         em= ((Mesh*)obedit->data)->edit_btmesh;
1554         ima= CTX_data_edit_image(C);
1555         
1556         if(ts->uv_flag & UV_SYNC_SELECTION) {
1557
1558                 switch (action) {
1559                 case SEL_TOGGLE:
1560                         EDBM_toggle_select_all(((Mesh*)obedit->data)->edit_btmesh);
1561                         break;
1562                 case SEL_SELECT:
1563                         EDBM_set_flag_all(em, BM_SELECT);
1564                         break;
1565                 case SEL_DESELECT:
1566                         EDBM_clear_flag_all(em, BM_SELECT);
1567                         break;
1568                 case SEL_INVERT:
1569                         EDBM_select_swap(em);
1570                         break;
1571                 }
1572         }
1573         else {
1574                 if (action == SEL_TOGGLE) {
1575                         action = SEL_SELECT;
1576                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1577                                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1578         
1579                                 if(!uvedit_face_visible(scene, ima, efa, tf))
1580                                         continue;
1581
1582                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1583                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1584
1585                                         if (luv->flag & MLOOPUV_VERTSEL) {
1586                                                 action = SEL_DESELECT;
1587                                                 break;
1588                                         }
1589                                 }
1590                         }
1591                 }
1592         
1593                 
1594                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1595                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1596
1597                         if(!uvedit_face_visible(scene, ima, efa, tf))
1598                                 continue;
1599
1600                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1601                                 char select_flag;
1602
1603                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1604
1605                                 select_flag = luv->flag & MLOOPUV_VERTSEL;
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 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_flush_update(obedit->data, OB_RECALC_DATA);
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 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 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_flush_update(obedit->data, OB_RECALC_DATA);
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 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 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_flush_update(obedit->data, OB_RECALC_DATA);
2192         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2193
2194         return OPERATOR_FINISHED;
2195 }
2196
2197 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 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, 
2480                                      Scene *scene, int select, float *offset,
2481                                      float *ell, BMLoop *l, MLoopUV *luv)
2482 {
2483         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
2484         float x, y, r2, *uv;
2485         
2486         
2487         uv= luv->uv;
2488
2489         x= (uv[0] - offset[0])*ell[0];
2490         y= (uv[1] - offset[1])*ell[1];
2491
2492         r2 = x*x + y*y;
2493         if(r2 < 1.0) {
2494                 if(select) uvedit_uv_select(em, scene, l);
2495                 else uvedit_uv_deselect(em, scene, l);
2496         }
2497 }
2498
2499 int circle_select_exec(bContext *C, wmOperator *op)
2500 {
2501         SpaceImage *sima= CTX_wm_space_image(C);
2502         Scene *scene= CTX_data_scene(C);
2503         Object *obedit= CTX_data_edit_object(C);
2504         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2505         ARegion *ar= CTX_wm_region(C);
2506         BMFace *efa;
2507         BMLoop *l;
2508         BMIter iter, liter;
2509         MLoopUV *luv;
2510         MTexPoly *tface;
2511         int x, y, radius, width, height, select;
2512         float zoomx, zoomy, offset[2], ellipse[2];
2513         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
2514     
2515         /* get operator properties */
2516         select= (gesture_mode == GESTURE_MODAL_SELECT);
2517         x= RNA_int_get(op->ptr, "x");
2518         y= RNA_int_get(op->ptr, "y");
2519         radius= RNA_int_get(op->ptr, "radius");
2520
2521         /* compute ellipse size and location, not a circle since we deal
2522          * with non square image. ellipse is normalized, r = 1.0. */
2523         ED_space_image_size(sima, &width, &height);
2524         ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
2525
2526         ellipse[0]= width*zoomx/radius;
2527         ellipse[1]= height*zoomy/radius;
2528
2529         UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
2530         
2531         /* do selection */
2532         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2533                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2534                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2535                         select_uv_inside_ellipse(em, sima, scene, select, offset, ellipse, l, luv);
2536                 }
2537         }
2538
2539 #if 0 //I think the BM_Select api stuff handles all this as necassary?
2540         if(select) EM_select_flush(em);
2541         else EM_deselect_flush(em);
2542 #endif
2543         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2544
2545         return OPERATOR_FINISHED;
2546 }
2547
2548 void UV_OT_circle_select(wmOperatorType *ot)
2549 {
2550         /* identifiers */
2551         ot->name= "Circle Select";
2552         ot->description= "Select UV vertices using circle selection";
2553         ot->idname= "UV_OT_circle_select";
2554         
2555         /* api callbacks */
2556         ot->invoke= WM_gesture_circle_invoke;
2557         ot->modal= WM_gesture_circle_modal;
2558         ot->exec= circle_select_exec;
2559         ot->poll= ED_operator_uvedit;
2560         
2561         /* flags */
2562         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2563         
2564         /* properties */
2565         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2566         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2567         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
2568         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
2569 }
2570
2571 /* ******************** snap cursor operator **************** */
2572
2573 static void snap_uv_to_pixel(float *uvco, float w, float h)
2574 {
2575         uvco[0] = ((float)((int)((uvco[0]*w) + 0.5f)))/w;
2576         uvco[1] = ((float)((int)((uvco[1]*h) + 0.5f)))/h;
2577 }
2578
2579 static void snap_cursor_to_pixels(SpaceImage *sima)
2580 {
2581         int width= 0, height= 0;
2582
2583         ED_space_image_size(sima, &width, &height);
2584         snap_uv_to_pixel(sima->cursor, width, height);
2585 }
2586
2587 static int snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2588 {
2589         return uvedit_center(scene, ima, obedit, sima->cursor, 0);
2590 }
2591
2592 static int snap_cursor_exec(bContext *C, wmOperator *op)
2593 {
2594         SpaceImage *sima= CTX_wm_space_image(C);
2595         Scene *scene= CTX_data_scene(C);
2596         Object *obedit= CTX_data_edit_object(C);
2597         Image *ima= CTX_data_edit_image(C);
2598         int change= 0;
2599
2600         switch(RNA_boolean_get(op->ptr, "target")) {
2601                 case 0:
2602                         snap_cursor_to_pixels(sima);
2603                         change= 1;
2604                         break;
2605                 case 1:
2606                         change= snap_cursor_to_selection(scene, ima, obedit, sima);
2607                         break;
2608         }
2609
2610         if(!change)
2611                 return OPERATOR_CANCELLED;
2612         
2613         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, sima);
2614
2615         return OPERATOR_FINISHED;
2616 }
2617
2618 void UV_OT_snap_cursor(wmOperatorType *ot)
2619 {
2620         static EnumPropertyItem target_items[] = {
2621                 {0, "PIXELS", 0, "Pixels", ""},
2622                 {1, "SELECTION", 0, "Selection", ""},
2623                 {0, NULL, 0, NULL, NULL}};
2624
2625         /* identifiers */
2626         ot->name= "Snap Cursor";
2627         ot->description= "Snap cursor to target type";
2628         ot->idname= "UV_OT_snap_cursor";
2629         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2630         
2631         /* api callbacks */
2632         ot->exec= snap_cursor_exec;
2633         ot->poll= ED_operator_uvedit;
2634
2635         /* properties */
2636         RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UV's to.");
2637 }
2638
2639 /* ******************** snap selection operator **************** */
2640
2641 static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2642 {
2643         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2644         BMFace *efa;
2645         BMLoop *l;
2646         BMIter iter, liter;
2647         MTexPoly *tface;
2648         MLoopUV *luv;
2649         short change= 0;
2650
2651         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2652                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2653                 if(!uvedit_face_visible(scene, ima, efa, tface))
2654                         continue;
2655
2656                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2657                         if(uvedit_uv_selected(em, scene, l)) {
2658                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2659                                 VECCOPY2D(luv->uv, sima->cursor);
2660                                 change= 1;
2661                         }
2662                 }
2663         }
2664
2665         return change;
2666 }
2667
2668 static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
2669 {
2670         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2671         BMFace *efa;
2672         BMLoop *l;
2673         BMIter iter, liter;
2674         BMVert *eve;
2675         MTexPoly *tface;
2676         MLoopUV *luv;
2677         short change = 0;
2678         int count = 0;
2679         float *coords;
2680         short *usercount, users;
2681         
2682         /* set all verts to -1 : an unused index*/
2683         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
2684                 BMINDEX_SET(eve, -1);
2685         
2686         /* index every vert that has a selected UV using it, but only once so as to
2687          * get unique indicies and to count how much to malloc */
2688         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2689                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2690                 if(!uvedit_face_visible(scene, ima, efa, tface)) {
2691                         BMINDEX_SET(efa, 0);
2692                         continue;
2693                 } else {
2694                         BMINDEX_SET(efa, 1);
2695                 }
2696
2697                 change = 1;
2698                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2699                         if (uvedit_uv_selected(em, scene, l) && BMINDEX_GET(l->v) == -1) {
2700                                 BMINDEX_SET(l->v, count);
2701                                 count++;
2702                         }
2703                 }
2704         }
2705         
2706         coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
2707         usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
2708         
2709         /* add all UV coords from visible, unselected UV coords as well as counting them to average later */
2710         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2711                 if (!BMINDEX_GET(efa))
2712                         continue;
2713
2714                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2715                 if(!uvedit_face_visible(scene, ima, efa, tface))
2716                         continue;
2717
2718                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2719                         if (BMINDEX_GET(l->v) >= 0 && 
2720                             (!uvedit_uv_selected(em, scene, l))) {
2721                                     luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2722                                     coords[BMINDEX_GET(l->v)*2] += luv->uv[0];
2723                                     coords[BMINDEX_GET(l->v)*2+1] += luv->uv[1];
2724                                     change = 1;
2725                         }
2726                 }
2727         }
2728         
2729         /* no other verts selected, bail out */
2730         if(!change) {
2731                 MEM_freeN(coords);
2732                 MEM_freeN(usercount);
2733                 return change;
2734         }
2735         
2736         /* copy the averaged unselected UVs back to the selected UVs */
2737         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2738                 if (!BMINDEX_GET(efa))
2739                         continue;
2740
2741                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2742                 if(!uvedit_face_visible(scene, ima, efa, tface))
2743                         continue;
2744
2745                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2746                         if (uvedit_uv_selected(em, scene, l) && BMINDEX_GET(l->v) >= 0
2747                             && (users = usercount[BMINDEX_GET(l->v)])) {
2748                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2749                                 luv->uv[0] = coords[BMINDEX_GET(l->v)*2];
2750                                 luv->uv[1] = coords[BMINDEX_GET(l->v)*2+1];
2751                         }
2752                 }
2753         }
2754         
2755         MEM_freeN(coords);
2756         MEM_freeN(usercount);
2757
2758         return change;
2759 }
2760
2761 static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
2762 {
2763         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2764         Image *ima= sima->image;
2765         BMFace *efa;
2766         BMLoop *l;
2767         BMIter iter, liter;
2768         MTexPoly *tface;
2769         MLoopUV *luv;
2770         int width= 0, height= 0;
2771         float w, h;
2772         short change = 0;
2773
2774         ED_space_image_size(sima, &width, &height);
2775         w = (float)width;
2776         h = (float)height;
2777         
2778         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2779                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2780                 if(!uvedit_face_visible(scene, ima, efa, tface))
2781                         continue;
2782
2783                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2784                         if (uvedit_uv_selected(em, scene, l)) {
2785                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2786                                 snap_uv_to_pixel(luv->uv, w, h);
2787                         }
2788                 }
2789
2790                 change = 1;
2791         }
2792
2793         return change;
2794 }
2795
2796 static int snap_selection_exec(bContext *C, wmOperator *op)
2797 {
2798         SpaceImage *sima= CTX_wm_space_image(C);
2799         Scene *scene= CTX_data_scene(C);
2800         Object *obedit= CTX_data_edit_object(C);
2801         Image *ima= CTX_data_edit_image(C);
2802         int change= 0;
2803
2804         switch(RNA_boolean_get(op->ptr, "target")) {
2805                 case 0:
2806                         change= snap_uvs_to_pixels(sima, scene, obedit);
2807                         break;
2808                 case 1:
2809                         change= snap_uvs_to_cursor(scene, ima, obedit, sima);
2810                         break;
2811                 case 2:
2812                         change= snap_uvs_to_adjacent_unselected(scene, ima, obedit);
2813                         break;
2814         }
2815
2816         if(!change)
2817                 return OPERATOR_CANCELLED;
2818         
2819         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2820         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2821
2822         return OPERATOR_FINISHED;
2823 }
2824
2825 void UV_OT_snap_selection(wmOperatorType *ot)
2826 {
2827         static EnumPropertyItem target_items[] = {
2828                 {0, "PIXELS", 0, "Pixels", ""},
2829                 {1, "CURSOR", 0, "Cursor", ""},
2830                 {2, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
2831                 {0, NULL, 0, NULL, NULL}};
2832
2833         /* identifiers */
2834         ot->name= "Snap Selection";
2835         ot->description= "Snap selected UV vertices to target type";
2836         ot->idname= "UV_OT_snap_selection";
2837         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2838         
2839         /* api callbacks */
2840         ot->exec= snap_selection_exec;
2841         ot->poll= ED_operator_uvedit;
2842
2843         /* properties */
2844         RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UV's to.");
2845 }
2846
2847 /* ******************** pin operator **************** */
2848
2849 static int pin_exec(bContext *C, wmOperator *op)
2850 {
2851         Scene *scene= CTX_data_scene(C);
2852         Object *obedit= CTX_data_edit_object(C);
2853         Image *ima= CTX_data_edit_image(C);
2854         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2855         BMFace *efa;
2856         BMLoop *l;
2857         BMIter iter, liter;
2858         MTexPoly *tface;
2859         MLoopUV *luv;
2860         int clear= RNA_boolean_get(op->ptr, "clear");
2861         
2862         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2863                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2864                 if(!uvedit_face_visible(scene, ima, efa, tface))
2865                         continue;
2866
2867                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2868                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2869                         
2870                         if(!clear) {
2871                                 if (uvedit_uv_selected(em, scene, l))
2872                                         luv->flag |= MLOOPUV_PINNED;
2873                         } else {
2874                                 if (uvedit_uv_selected(em, scene, l))
2875                                         luv->flag &= ~MLOOPUV_PINNED;
2876                         }
2877                 }
2878         }
2879         
2880         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2881
2882         return OPERATOR_FINISHED;
2883 }
2884
2885 void UV_OT_pin(wmOperatorType *ot)
2886 {
2887         /* identifiers */
2888         ot->name= "Pin";
2889         ot->description= "Set/clear selected UV vertices as anchored between multiple unwrap operations";
2890         ot->idname= "UV_OT_pin";
2891         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2892         
2893         /* api callbacks */
2894         ot->exec= pin_exec;
2895         ot->poll= ED_operator_uvedit;
2896
2897         /* properties */
2898         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it.");
2899 }
2900
2901 /******************* select pinned operator ***************/
2902
2903 static int select_pinned_exec(bContext *C, wmOperator *op)
2904 {
2905         Scene *scene= CTX_data_scene(C);
2906         Object *obedit= CTX_data_edit_object(C);
2907         Image *ima= CTX_data_edit_image(C);
2908         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2909         BMFace *efa;
2910         BMLoop *l;
2911         BMIter iter, liter;
2912         MTexPoly *tface;
2913         MLoopUV *luv;
2914         
2915         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2916                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2917                 if(!uvedit_face_visible(scene, ima, efa, tface))
2918                         continue;
2919
2920                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2921                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2922                         
2923                         if (luv->flag & MLOOPUV_PINNED)
2924                                 uvedit_uv_select(em, scene, l);
2925                 }
2926         }
2927         
2928         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2929
2930         return OPERATOR_FINISHED;
2931 }
2932
2933 void UV_OT_select_pinned(wmOperatorType *ot)
2934 {
2935         /* identifiers */
2936         ot->name= "Selected Pinned";
2937         ot->description= "Select all pinned UV vertices";
2938         ot->idname= "UV_OT_select_pinned";
2939         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2940         
2941         /* api callbacks */
2942         ot->exec= select_pinned_exec;
2943         ot->poll= ED_operator_uvedit;
2944 }
2945
2946 /********************** hide operator *********************/
2947
2948 static int hide_exec(bContext *C, wmOperator *op)
2949 {
2950         SpaceImage *sima= CTX_wm_space_image(C);
2951         ToolSettings *ts= CTX_data_tool_settings(C);
2952         Object *obedit= CTX_data_edit_object(C);
2953         Scene *scene = CTX_data_scene(C);
2954         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2955         BMFace *efa;
2956         BMLoop *l;
2957         BMIter iter, liter;
2958         MTexPoly *tf;
2959         MLoopUV *luv;
2960         int swap= RNA_boolean_get(op->ptr, "unselected");
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                         BM_Select(em->bm, efa, 0);
2986                         uvedit_face_deselect(scene, em, efa);
2987                 }
2988         }
2989         
2990         ///*deselects too many but ok for now*/
2991         //if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX))
2992         //      EM_deselect_flush(em);
2993         
2994         
2995         EDBM_validate_selections(em);
2996         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2997
2998         return OPERATOR_FINISHED;
2999 }
3000
3001 void UV_OT_hide(wmOperatorType *ot)
3002 {
3003         /* identifiers */
3004         ot->name= "Hide Selected";
3005         ot->description= "Hide (un)selected UV vertices";
3006         ot->idname= "UV_OT_hide";
3007         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3008         
3009         /* api callbacks */
3010         ot->exec= hide_exec;
3011         ot->poll= ED_operator_uvedit;
3012
3013         /* props */
3014         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
3015 }
3016
3017 /****************** reveal operator ******************/
3018
3019 static int reveal_exec(bContext *C, wmOperator *op)
3020 {
3021         SpaceImage *sima= CTX_wm_space_image(C);
3022         ToolSettings *ts= CTX_data_tool_settings(C);
3023         Object *obedit= CTX_data_edit_object(C);
3024         Scene *scene = CTX_data_scene(C);
3025         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
3026         BMFace *efa;
3027         BMLoop *l;
3028         BMVert *v;
3029         BMIter iter, liter;
3030         MTexPoly *tf;
3031         MLoopUV *luv;
3032         
3033         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
3034                 BMINDEX_SET(v, BM_TestHFlag(v, BM_SELECT));
3035         }
3036
3037         /* call the mesh function if we are in mesh sync sel */
3038         if(ts->uv_flag & UV_SYNC_SELECTION) {
3039                 EDBM_reveal_mesh(em);
3040                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
3041
3042                 return OPERATOR_FINISHED;
3043         }
3044
3045         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
3046                 if (em->selectmode == SCE_SELECT_FACE) {
3047                         uvedit_face_select(scene, em, efa);
3048                 } else {
3049                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
3050                                 if (!BMINDEX_GET(l->v)) {
3051                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
3052                                         luv->flag |= MLOOPUV_VERTSEL;
3053                                 }
3054                         }
3055                 }
3056
3057                 BM_Select(em->bm, efa, 1);
3058         }
3059
3060         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
3061
3062         return OPERATOR_FINISHED;
3063 }
3064
3065 void UV_OT_reveal(wmOperatorType *ot)
3066 {
3067         /* identifiers */
3068         ot->name= "Reveal Hidden";
3069         ot->description= "Reveal all hidden UV vertices";
3070         ot->idname= "UV_OT_reveal";
3071         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3072         
3073         /* api callbacks */
3074         ot->exec= reveal_exec;
3075         ot->poll= ED_operator_uvedit;
3076 }
3077
3078 /******************** set 3d cursor operator ********************/
3079
3080 static int set_2d_cursor_exec(bContext *C, wmOperator *op)
3081 {
3082         SpaceImage *sima = CTX_wm_space_image(C);
3083         float location[2];
3084
3085         RNA_float_get_array(op->ptr, "location", location);
3086         sima->cursor[0]= location[0];
3087         sima->cursor[1]= location[1];
3088         
3089         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, NULL);
3090         
3091         return OPERATOR_FINISHED;
3092 }
3093
3094 static int set_2d_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
3095 {
3096         ARegion *ar= CTX_wm_region(C);
3097         int x, y;
3098         float location[2];
3099
3100         x= event->x - ar->winrct.xmin;
3101         y= event->y - ar->winrct.ymin;
3102         UI_view2d_region_to_view(&ar->v2d, x, y, &location[0], &location[1]);
3103         RNA_float_set_array(op->ptr, "location", location);
3104
3105         return set_2d_cursor_exec(C, op);
3106 }
3107
3108 void UV_OT_cursor_set(wmOperatorType *ot)
3109 {
3110         /* identifiers */
3111         ot->name= "Set 2D Cursor";
3112         ot->description= "Set 2D cursor location";
3113         ot->idname= "UV_OT_cursor_set";
3114         
3115         /* api callbacks */
3116         ot->exec= set_2d_cursor_exec;
3117         ot->invoke= set_2d_cursor_invoke;
3118         ot->poll= ED_operator_uvedit;
3119
3120         /* flags */
3121         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3122
3123         /* properties */
3124         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);
3125 }
3126
3127 /********************** set tile operator **********************/
3128
3129 static int set_tile_exec(bContext *C, wmOperator *op)
3130 {
3131         Image *ima= CTX_data_edit_image(C);
3132         int tile[2];
3133
3134         if(!ima || !(ima->tpageflag & IMA_TILES))
3135                 return OPERATOR_CANCELLED;
3136
3137         RNA_int_get_array(op->ptr, "tile", tile);
3138         ED_uvedit_set_tile(C, CTX_data_scene(C), CTX_data_edit_object(C), ima, tile[0] + ima->xrep*tile[1]);
3139
3140         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, NULL);
3141
3142         return OPERATOR_FINISHED;
3143 }
3144
3145 static int set_tile_invoke(bContext *C, wmOperator *op, wmEvent *event)
3146 {
3147         SpaceImage *sima= CTX_wm_space_image(C);
3148         Image *ima= CTX_data_edit_image(C);
3149         ARegion *ar= CTX_wm_region(C);
3150         float fx, fy;
3151         int x, y, tile[2];
3152
3153         if(!ima || !(ima->tpageflag & IMA_TILES))
3154                 return OPERATOR_CANCELLED;
3155
3156         x= event->x - ar->winrct.xmin;
3157         y= event->y - ar->winrct.ymin;
3158         UI_view2d_region_to_view(&ar->v2d, x, y, &fx, &fy);
3159
3160         if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
3161                 fx= fx*ima->xrep;
3162                 fy= fy*ima->yrep;
3163                 
3164                 tile[0]= fx;
3165                 tile[1]= fy;
3166                 
3167                 sima->curtile= tile[1]*ima->xrep + tile[0];
3168                 RNA_int_set_array(op->ptr, "tile", tile);
3169         }
3170
3171         return set_tile_exec(C, op);
3172 }
3173
3174 void UV_OT_tile_set(wmOperatorType *ot)
3175 {
3176         /* identifiers */
3177         ot->name= "Set Tile";
3178         ot->description= "Set UV image tile coordinates";
3179         ot->idname= "UV_OT_tile_set";
3180         
3181         /* api callbacks */
3182         ot->exec= set_tile_exec;
3183         ot->invoke= set_tile_invoke;
3184         ot->poll= ED_operator_uvedit;
3185
3186         /* flags */
3187         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3188
3189         /* properties */
3190         RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate.", 0, 10);
3191 }
3192
3193 /* ************************** registration **********************************/
3194
3195 void ED_operatortypes_uvedit(void)
3196 {
3197         WM_operatortype_append(UV_OT_select_all);
3198         WM_operatortype_append(UV_OT_select_inverse);