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