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