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