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